Bug 1362098 - Add source position to requested module information r=till
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 23 Aug 2017 17:24:37 +0100
changeset 425890 a953b8493339d0542ca6accd7cb35748b5b60c85
parent 425889 e1d01918122f121ccafd131b62e7dc848d547d7e
child 425891 514a186794df174afa46187a234586e5351b4c92
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1362098
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1362098 - Add source position to requested module information r=till
js/public/Class.h
js/src/builtin/Module.js
js/src/builtin/ModuleObject.cpp
js/src/builtin/ModuleObject.h
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/gc/Policy.h
js/src/jit-test/tests/modules/requested-modules.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -855,17 +855,17 @@ static const uint32_t JSCLASS_FOREGROUND
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
 // the beginning of every global object's slots for use by the
 // application.
 static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5;
 static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT =
-    JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 36;
+    JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37;
 
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                              \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -376,17 +376,17 @@ function InnerModuleDeclarationInstantia
     index++;
 
     // Step 9
     _DefineDataProperty(stack, stack.length, module);
 
     // Step 10
     let requestedModules = module.requestedModules;
     for (let i = 0; i < requestedModules.length; i++) {
-        let required = requestedModules[i];
+        let required = requestedModules[i].moduleSpecifier;
         let requiredModule = CallModuleResolveHook(module, required, MODULE_STATUS_ERRORED);
 
         index = InnerModuleDeclarationInstantiation(requiredModule, stack, index);
 
         assert(requiredModule.status === MODULE_STATUS_INSTANTIATING ||
                requiredModule.status === MODULE_STATUS_INSTANTIATED ||
                requiredModule.status === MODULE_STATUS_EVALUATED,
                "Bad required module status after InnerModuleDeclarationInstantiation");
@@ -595,17 +595,17 @@ function InnerModuleEvaluation(module, s
     index++;
 
     // Step 9
     _DefineDataProperty(stack, stack.length, module);
 
     // Step 10
     let requestedModules = module.requestedModules;
     for (let i = 0; i < requestedModules.length; i++) {
-        let required = requestedModules[i];
+        let required = requestedModules[i].moduleSpecifier;
         let requiredModule =
             CallModuleResolveHook(module, required, MODULE_STATUS_INSTANTIATED);
 
         index = InnerModuleEvaluation(requiredModule, stack, index);
 
         assert(requiredModule.status == MODULE_STATUS_EVALUATING ||
                requiredModule.status == MODULE_STATUS_EVALUATED,
               "Bad module status after InnerModuleEvaluation");
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -123,17 +123,17 @@ GlobalObject::initImportEntryProto(JSCon
 
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return false;
 
     if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr))
         return false;
 
-    global->setReservedSlot(IMPORT_ENTRY_PROTO, ObjectValue(*proto));
+    global->initReservedSlot(IMPORT_ENTRY_PROTO, ObjectValue(*proto));
     return true;
 }
 
 /* static */ ImportEntryObject*
 ImportEntryObject::create(JSContext* cx,
                           HandleAtom moduleRequest,
                           HandleAtom importName,
                           HandleAtom localName,
@@ -201,17 +201,17 @@ GlobalObject::initExportEntryProto(JSCon
 
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return false;
 
     if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr))
         return false;
 
-    global->setReservedSlot(EXPORT_ENTRY_PROTO, ObjectValue(*proto));
+    global->initReservedSlot(EXPORT_ENTRY_PROTO, ObjectValue(*proto));
     return true;
 }
 
 static Value
 StringOrNullValue(JSString* maybeString)
 {
     return maybeString ? StringValue(maybeString) : NullValue();
 }
@@ -239,16 +239,81 @@ ExportEntryObject::create(JSContext* cx,
     self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
     self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
     self->initReservedSlot(LineNumberSlot, Int32Value(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, Int32Value(columnNumber));
     return self;
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// RequestedModuleObject
+
+/* static */ const Class
+RequestedModuleObject::class_ = {
+    "RequestedModule",
+    JSCLASS_HAS_RESERVED_SLOTS(RequestedModuleObject::SlotCount) |
+    JSCLASS_IS_ANONYMOUS
+};
+
+DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, moduleSpecifier, ModuleSpecifierSlot)
+DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, lineNumber, LineNumberSlot)
+DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, columnNumber, ColumnNumberSlot)
+
+DEFINE_ATOM_ACCESSOR_METHOD(RequestedModuleObject, moduleSpecifier)
+DEFINE_UINT32_ACCESSOR_METHOD(RequestedModuleObject, lineNumber)
+DEFINE_UINT32_ACCESSOR_METHOD(RequestedModuleObject, columnNumber)
+
+/* static */ bool
+RequestedModuleObject::isInstance(HandleValue value)
+{
+    return value.isObject() && value.toObject().is<RequestedModuleObject>();
+}
+
+/* static */ bool
+GlobalObject::initRequestedModuleProto(JSContext* cx, Handle<GlobalObject*> global)
+{
+    static const JSPropertySpec protoAccessors[] = {
+        JS_PSG("moduleSpecifier", RequestedModuleObject_moduleSpecifierGetter, 0),
+        JS_PSG("lineNumber", RequestedModuleObject_lineNumberGetter, 0),
+        JS_PSG("columnNumber", RequestedModuleObject_columnNumberGetter, 0),
+        JS_PS_END
+    };
+
+    RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
+    if (!proto)
+        return false;
+
+    if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr))
+        return false;
+
+    global->initReservedSlot(REQUESTED_MODULE_PROTO, ObjectValue(*proto));
+    return true;
+}
+
+/* static */ RequestedModuleObject*
+RequestedModuleObject::create(JSContext* cx,
+                              HandleAtom moduleSpecifier,
+                              uint32_t lineNumber,
+                              uint32_t columnNumber)
+{
+    MOZ_ASSERT(lineNumber > 0);
+
+    RootedObject proto(cx, cx->global()->getRequestedModulePrototype());
+    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
+    if (!obj)
+        return nullptr;
+
+    RootedRequestedModuleObject self(cx, &obj->as<RequestedModuleObject>());
+    self->initReservedSlot(ModuleSpecifierSlot, StringValue(moduleSpecifier));
+    self->initReservedSlot(LineNumberSlot, Int32Value(lineNumber));
+    self->initReservedSlot(ColumnNumberSlot, Int32Value(columnNumber));
+    return self;
+}
+
+///////////////////////////////////////////////////////////////////////////
 // IndirectBindingMap
 
 IndirectBindingMap::Binding::Binding(ModuleEnvironmentObject* environment, Shape* shape)
   : environment(environment), shape(shape)
 {}
 
 IndirectBindingMap::IndirectBindingMap(Zone* zone)
   : map_(ZoneAllocPolicy(zone))
@@ -1075,26 +1140,33 @@ GlobalObject::initModuleProto(JSContext*
 ///////////////////////////////////////////////////////////////////////////
 // ModuleBuilder
 
 ModuleBuilder::ModuleBuilder(JSContext* cx, HandleModuleObject module,
                              const frontend::TokenStream& tokenStream)
   : cx_(cx),
     module_(cx, module),
     tokenStream_(tokenStream),
-    requestedModules_(cx, AtomVector(cx)),
+    requestedModuleSpecifiers_(cx, AtomSet(cx)),
+    requestedModules_(cx, RequestedModuleVector(cx)),
     importedBoundNames_(cx, AtomVector(cx)),
     importEntries_(cx, ImportEntryVector(cx)),
     exportEntries_(cx, ExportEntryVector(cx)),
     localExportEntries_(cx, ExportEntryVector(cx)),
     indirectExportEntries_(cx, ExportEntryVector(cx)),
     starExportEntries_(cx, ExportEntryVector(cx))
 {}
 
 bool
+ModuleBuilder::init()
+{
+    return requestedModuleSpecifiers_.init();
+}
+
+bool
 ModuleBuilder::buildTables()
 {
     for (const auto& e : exportEntries_) {
         RootedExportEntryObject exp(cx_, e);
         if (!exp->moduleRequest()) {
             RootedImportEntryObject importEntry(cx_, importEntryFor(exp->localName()));
             if (!importEntry) {
                 if (!localExportEntries_.append(exp))
@@ -1131,34 +1203,33 @@ ModuleBuilder::buildTables()
     }
 
     return true;
 }
 
 bool
 ModuleBuilder::initModule()
 {
-    RootedArrayObject requestedModules(cx_, createArray<JSAtom*>(requestedModules_));
+    RootedArrayObject requestedModules(cx_, createArray(requestedModules_));
     if (!requestedModules)
         return false;
 
-    RootedArrayObject importEntries(cx_, createArray<ImportEntryObject*>(importEntries_));
+    RootedArrayObject importEntries(cx_, createArray(importEntries_));
     if (!importEntries)
         return false;
 
-    RootedArrayObject localExportEntries(cx_, createArray<ExportEntryObject*>(localExportEntries_));
+    RootedArrayObject localExportEntries(cx_, createArray(localExportEntries_));
     if (!localExportEntries)
         return false;
 
-    RootedArrayObject indirectExportEntries(cx_);
-    indirectExportEntries = createArray<ExportEntryObject*>(indirectExportEntries_);
+    RootedArrayObject indirectExportEntries(cx_, createArray(indirectExportEntries_));
     if (!indirectExportEntries)
         return false;
 
-    RootedArrayObject starExportEntries(cx_, createArray<ExportEntryObject*>(starExportEntries_));
+    RootedArrayObject starExportEntries(cx_, createArray(starExportEntries_));
     if (!starExportEntries)
         return false;
 
     module_->initImportExportData(requestedModules,
                                  importEntries,
                                  localExportEntries,
                                  indirectExportEntries,
                                  starExportEntries);
@@ -1170,17 +1241,17 @@ bool
 ModuleBuilder::processImport(frontend::ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_IMPORT));
     MOZ_ASSERT(pn->isArity(PN_BINARY));
     MOZ_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
     MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
 
     RootedAtom module(cx_, pn->pn_right->pn_atom);
-    if (!maybeAppendRequestedModule(module))
+    if (!maybeAppendRequestedModule(module, pn->pn_right))
         return false;
 
     for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) {
         MOZ_ASSERT(spec->isKind(PNK_IMPORT_SPEC));
         MOZ_ASSERT(spec->pn_left->isArity(PN_NAME));
         MOZ_ASSERT(spec->pn_right->isArity(PN_NAME));
 
         RootedAtom importName(cx_, spec->pn_left->pn_atom);
@@ -1278,17 +1349,17 @@ bool
 ModuleBuilder::processExportFrom(frontend::ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_EXPORT_FROM));
     MOZ_ASSERT(pn->isArity(PN_BINARY));
     MOZ_ASSERT(pn->pn_left->isKind(PNK_EXPORT_SPEC_LIST));
     MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
 
     RootedAtom module(cx_, pn->pn_right->pn_atom);
-    if (!maybeAppendRequestedModule(module))
+    if (!maybeAppendRequestedModule(module, pn->pn_right))
         return false;
 
     for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) {
         if (spec->isKind(PNK_EXPORT_SPEC)) {
             RootedAtom bindingName(cx_, spec->pn_left->pn_atom);
             RootedAtom exportName(cx_, spec->pn_right->pn_atom);
             if (!appendExportFromEntry(exportName, module, bindingName, spec->pn_left))
                 return false;
@@ -1347,43 +1418,41 @@ ModuleBuilder::appendExportFromEntry(Han
 
     Rooted<ExportEntryObject*> exportEntry(cx_);
     exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr,
                                             line, column);
     return exportEntry && exportEntries_.append(exportEntry);
 }
 
 bool
-ModuleBuilder::maybeAppendRequestedModule(HandleAtom module)
+ModuleBuilder::maybeAppendRequestedModule(HandleAtom specifier, ParseNode* node)
 {
-    for (auto m : requestedModules_) {
-        if (m == module)
-            return true;
-    }
-    return requestedModules_.append(module);
-}
+    if (requestedModuleSpecifiers_.has(specifier))
+        return true;
+
+    uint32_t line;
+    uint32_t column;
+    tokenStream_.lineNumAndColumnIndex(node->pn_pos.begin, &line, &column);
 
-static Value
-MakeElementValue(JSString *string)
-{
-    return StringValue(string);
-}
+    JSContext* cx = cx_;
+    RootedRequestedModuleObject req(cx, RequestedModuleObject::create(cx, specifier, line, column));
+    if (!req)
+        return false;
 
-static Value
-MakeElementValue(JSObject *object)
-{
-    return ObjectValue(*object);
+    return FreezeObject(cx, req) &&
+           requestedModules_.append(req) &&
+           requestedModuleSpecifiers_.put(specifier);
 }
 
 template <typename T>
-ArrayObject* ModuleBuilder::createArray(const GCVector<T>& vector)
+ArrayObject* ModuleBuilder::createArray(const JS::Rooted<GCVector<T>>& vector)
 {
     uint32_t length = vector.length();
     RootedArrayObject array(cx_, NewDenseFullyAllocatedArray(cx_, length));
     if (!array)
         return nullptr;
 
     array->setDenseInitializedLength(length);
     for (uint32_t i = 0; i < length; i++)
-        array->initDenseElement(i, MakeElementValue(vector[i]));
+        array->initDenseElement(i, ObjectValue(*vector[i]));
 
     return array;
 }
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -94,16 +94,42 @@ class ExportEntryObject : public NativeO
     JSAtom* localName() const;
     uint32_t lineNumber() const;
     uint32_t columnNumber() const;
 };
 
 typedef Rooted<ExportEntryObject*> RootedExportEntryObject;
 typedef Handle<ExportEntryObject*> HandleExportEntryObject;
 
+class RequestedModuleObject : public NativeObject
+{
+  public:
+    enum
+    {
+        ModuleSpecifierSlot = 0,
+        LineNumberSlot,
+        ColumnNumberSlot,
+        SlotCount
+    };
+
+    static const Class class_;
+    static JSObject* initClass(JSContext* cx, HandleObject obj);
+    static bool isInstance(HandleValue value);
+    static RequestedModuleObject* create(JSContext* cx,
+                                         HandleAtom moduleSpecifier,
+                                         uint32_t lineNumber,
+                                         uint32_t columnNumber);
+    JSAtom* moduleSpecifier() const;
+    uint32_t lineNumber() const;
+    uint32_t columnNumber() const;
+};
+
+typedef Rooted<RequestedModuleObject*> RootedRequestedModuleObject;
+typedef Handle<RequestedModuleObject*> HandleRequestedModuleObject;
+
 class IndirectBindingMap
 {
   public:
     explicit IndirectBindingMap(Zone* zone);
     bool init();
 
     void trace(JSTracer* trc);
 
@@ -314,16 +340,17 @@ class ModuleObject : public NativeObject
 
 // Process a module's parse tree to collate the import and export data used when
 // creating a ModuleObject.
 class MOZ_STACK_CLASS ModuleBuilder
 {
   public:
     explicit ModuleBuilder(JSContext* cx, HandleModuleObject module,
                            const frontend::TokenStream& tokenStream);
+    bool init();
 
     bool processImport(frontend::ParseNode* pn);
     bool processExport(frontend::ParseNode* pn);
     bool processExportFrom(frontend::ParseNode* pn);
 
     bool hasExportedName(JSAtom* name) const;
 
     using ExportEntryVector = GCVector<ExportEntryObject*>;
@@ -331,43 +358,48 @@ class MOZ_STACK_CLASS ModuleBuilder
         return localExportEntries_;
     }
 
     bool buildTables();
     bool initModule();
 
   private:
     using AtomVector = GCVector<JSAtom*>;
+    using ImportEntryVector = GCVector<ImportEntryObject*>;
+    using RequestedModuleVector = GCVector<RequestedModuleObject*>;
+    using AtomSet = JS::GCHashSet<JSAtom*>;
     using RootedAtomVector = JS::Rooted<AtomVector>;
-    using ImportEntryVector = GCVector<ImportEntryObject*>;
     using RootedImportEntryVector = JS::Rooted<ImportEntryVector>;
     using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
+    using RootedRequestedModuleVector = JS::Rooted<RequestedModuleVector>;
+    using RootedAtomSet = JS::Rooted<AtomSet>;
 
     JSContext* cx_;
     RootedModuleObject module_;
     const frontend::TokenStream& tokenStream_;
-    RootedAtomVector requestedModules_;
+    RootedAtomSet requestedModuleSpecifiers_;
+    RootedRequestedModuleVector requestedModules_;
     RootedAtomVector importedBoundNames_;
     RootedImportEntryVector importEntries_;
     RootedExportEntryVector exportEntries_;
     RootedExportEntryVector localExportEntries_;
     RootedExportEntryVector indirectExportEntries_;
     RootedExportEntryVector starExportEntries_;
 
     ImportEntryObject* importEntryFor(JSAtom* localName) const;
 
     bool appendExportEntry(HandleAtom exportName, HandleAtom localName,
                            frontend::ParseNode* node = nullptr);
     bool appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
                                HandleAtom importName, frontend::ParseNode* node);
 
-    bool maybeAppendRequestedModule(HandleAtom module);
+    bool maybeAppendRequestedModule(HandleAtom specifier, frontend::ParseNode* node);
 
     template <typename T>
-    ArrayObject* createArray(const GCVector<T>& vector);
+    ArrayObject* createArray(const JS::Rooted<GCVector<T>>& vector);
 };
 
 } // namespace js
 
 template<>
 inline bool
 JSObject::is<js::ModuleNamespaceObject>() const
 {
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3737,16 +3737,19 @@ reflect_parse(JSContext* cx, uint32_t ar
         if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global()))
             return false;
 
         Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
         if (!module)
             return false;
 
         ModuleBuilder builder(cx, module, parser.tokenStream);
+        if (!builder.init())
+            return false;
+
         ModuleSharedContext modulesc(cx, module, &cx->global()->emptyGlobalScope(), builder);
         pn = parser.moduleBody(&modulesc);
         if (!pn)
             return false;
 
         MOZ_ASSERT(pn->getKind() == PNK_MODULE);
         pn = pn->pn_body;
     }
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -413,16 +413,19 @@ BytecodeCompiler::compileModule()
         return nullptr;
 
     if (!createScript())
         return nullptr;
 
     module->init(script);
 
     ModuleBuilder builder(cx, module, parser->tokenStream);
+    if (!builder.init())
+        return nullptr;
+
     ModuleSharedContext modulesc(cx, module, enclosingScope, builder);
     ParseNode* pn = parser->moduleBody(&modulesc);
     if (!pn)
         return nullptr;
 
     Maybe<BytecodeEmitter> emitter;
     if (!emplaceEmitter(emitter, &modulesc))
         return nullptr;
--- a/js/src/gc/Policy.h
+++ b/js/src/gc/Policy.h
@@ -42,16 +42,17 @@ class ModuleObject;
 class NativeObject;
 class ObjectGroup;
 class PlainObject;
 class PropertyName;
 class RegExpObject;
 class SavedFrame;
 class Scope;
 class EnvironmentObject;
+class RequestedModuleObject;
 class ScriptSourceObject;
 class Shape;
 class SharedArrayBufferObject;
 class StructTypeDescr;
 class UnownedBaseShape;
 class WasmFunctionScope;
 class WasmMemoryObject;
 namespace jit {
@@ -82,16 +83,17 @@ class JitCode;
     D(js::ModuleNamespaceObject*) \
     D(js::ModuleObject*) \
     D(js::NativeObject*) \
     D(js::ObjectGroup*) \
     D(js::PlainObject*) \
     D(js::PropertyName*) \
     D(js::RegExpObject*) \
     D(js::RegExpShared*) \
+    D(js::RequestedModuleObject*) \
     D(js::SavedFrame*) \
     D(js::Scope*) \
     D(js::ScriptSourceObject*) \
     D(js::Shape*) \
     D(js::SharedArrayBufferObject*) \
     D(js::StructTypeDescr*) \
     D(js::UnownedBaseShape*) \
     D(js::WasmFunctionScope*) \
--- a/js/src/jit-test/tests/modules/requested-modules.js
+++ b/js/src/jit-test/tests/modules/requested-modules.js
@@ -1,16 +1,16 @@
 // Test requestedModules property
 
 function testRequestedModules(source, expected) {
     var module = parseModule(source);
     var actual = module.requestedModules;
     assertEq(actual.length, expected.length);
     for (var i = 0; i < actual.length; i++) {
-        assertEq(actual[i], expected[i]);
+        assertEq(actual[i].moduleSpecifier, expected[i]);
     }
 }
 
 testRequestedModules("", []);
 
 testRequestedModules("import a from 'foo'",
                      ['foo']);
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4900,23 +4900,38 @@ JS_PUBLIC_API(JSObject*)
 JS::GetRequestedModules(JSContext* cx, JS::HandleObject moduleArg)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, moduleArg);
     return &moduleArg->as<ModuleObject>().requestedModules();
 }
 
-JS_PUBLIC_API(JSScript*)
-JS::GetModuleScript(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return moduleArg->as<ModuleObject>().script();
+JS_PUBLIC_API(JSString*)
+JS::GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue value)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, value);
+    JSObject* obj = &value.toObject();
+    return obj->as<RequestedModuleObject>().moduleSpecifier();
+}
+
+JS_PUBLIC_API(void)
+JS::GetRequestedModuleSourcePos(JSContext* cx, JS::HandleValue value,
+                                uint32_t* lineNumber, uint32_t* columnNumber)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, value);
+    MOZ_ASSERT(lineNumber);
+    MOZ_ASSERT(columnNumber);
+    auto& requested = value.toObject().as<RequestedModuleObject>();
+    *lineNumber = requested.lineNumber();
+    *columnNumber = requested.columnNumber();
 }
 
 JS_PUBLIC_API(bool)
 JS::IsModuleErrored(JSObject* moduleArg)
 {
     AssertHeapIsIdle();
     return moduleArg->as<ModuleObject>().status() == MODULE_STATUS_ERRORED;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4679,28 +4679,37 @@ ModuleInstantiate(JSContext* cx, JS::Han
  */
 extern JS_PUBLIC_API(bool)
 ModuleEvaluate(JSContext* cx, JS::HandleObject moduleRecord);
 
 /*
  * Get a list of the module specifiers used by a source text module
  * record to request importation of modules.
  *
- * The result is a JavaScript array of string values.  To extract the individual
- * values use only JS_GetArrayLength and JS_GetElement with indices 0 to
- * length - 1.
+ * The result is a JavaScript array of object values.  To extract the individual
+ * values use only JS_GetArrayLength and JS_GetElement with indices 0 to length
+ * - 1.
+ *
+ * The element values are objects with the following properties:
+ *  - moduleSpecifier: the module specifier string
+ *  - lineNumber: the line number of the import in the source text
+ *  - columnNumber: the column number of the import in the source text
+ *
+ * These property values can be extracted with GetRequestedModuleSpecifier() and
+ * GetRequestedModuleSourcePos()
  */
 extern JS_PUBLIC_API(JSObject*)
 GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord);
 
-/*
- * Get the script associated with a module.
- */
-extern JS_PUBLIC_API(JSScript*)
-GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord);
+extern JS_PUBLIC_API(JSString*)
+GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue requestedModuleObject);
+
+extern JS_PUBLIC_API(void)
+GetRequestedModuleSourcePos(JSContext* cx, JS::HandleValue requestedModuleObject,
+                            uint32_t* lineNumber, uint32_t* columnNumber);
 
 extern JS_PUBLIC_API(bool)
 IsModuleErrored(JSObject* moduleRecord);
 
 extern JS_PUBLIC_API(JS::Value)
 GetModuleError(JSObject* moduleRecord);
 
 } /* namespace JS */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -832,10 +832,11 @@ GlobalObject::addIntrinsicValue(JSContex
     return true;
 }
 
 /* static */ bool
 GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global)
 {
     return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto) &&
            getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, initImportEntryProto) &&
-           getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto);
+           getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto) &&
+           getOrCreateObject(cx, global, REQUESTED_MODULE_PROTO, initRequestedModuleProto);
 }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -94,16 +94,17 @@ class GlobalObject : public NativeObject
         NUMBER_FORMAT,
         NUMBER_FORMAT_PROTO,
         DATE_TIME_FORMAT,
         DATE_TIME_FORMAT_PROTO,
         PLURAL_RULES_PROTO,
         MODULE_PROTO,
         IMPORT_ENTRY_PROTO,
         EXPORT_ENTRY_PROTO,
+        REQUESTED_MODULE_PROTO,
         REGEXP_STATICS,
         RUNTIME_CODEGEN_ENABLED,
         DEBUGGERS,
         INTRINSICS,
         FOR_OF_PIC_CHAIN,
         MODULE_RESOLVE_HOOK,
         WINDOW_PROXY,
 
@@ -486,16 +487,21 @@ class GlobalObject : public NativeObject
         return value.isUndefined() ? nullptr : &value.toObject();
     }
 
     JSObject* maybeGetExportEntryPrototype() {
         Value value = getSlot(EXPORT_ENTRY_PROTO);
         return value.isUndefined() ? nullptr : &value.toObject();
     }
 
+    JSObject* maybeGetRequestedModulePrototype() {
+        Value value = getSlot(REQUESTED_MODULE_PROTO);
+        return value.isUndefined() ? nullptr : &value.toObject();
+    }
+
     JSObject* getModulePrototype() {
         JSObject* proto = maybeGetModulePrototype();
         MOZ_ASSERT(proto);
         return proto;
     }
 
     JSObject* getImportEntryPrototype() {
         JSObject* proto = maybeGetImportEntryPrototype();
@@ -504,16 +510,22 @@ class GlobalObject : public NativeObject
     }
 
     JSObject* getExportEntryPrototype() {
         JSObject* proto = maybeGetExportEntryPrototype();
         MOZ_ASSERT(proto);
         return proto;
     }
 
+    JSObject* getRequestedModulePrototype() {
+        JSObject* proto = maybeGetRequestedModulePrototype();
+        MOZ_ASSERT(proto);
+        return proto;
+    }
+
     static JSFunction*
     getOrCreateTypedArrayConstructor(JSContext* cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_TypedArray))
             return nullptr;
         return &global->getConstructor(JSProto_TypedArray).toObject().as<JSFunction>();
     }
 
     static JSObject*
@@ -764,16 +776,17 @@ class GlobalObject : public NativeObject
     // Implemented in Intl.cpp.
     static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
     static bool addPluralRulesConstructor(JSContext* cx, HandleObject intl);
 
     // Implemented in builtin/ModuleObject.cpp
     static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
+    static bool initRequestedModuleProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/TypedObject.cpp
     static bool initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/SIMD.cpp
     static bool initSimdObject(JSContext* cx, Handle<GlobalObject*> global);
     static bool initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType);