Bug 1309350: Part 1 - Remove dead code and clean up cruft. r=ochameau draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 13 Oct 2016 00:24:32 +0100
changeset 424545 95e39c47450b6cecd32cf2a73cdce4b31f5e3e11
parent 423958 558c51ec19e92741ca4df83bab25e8565a309c3a
child 424546 486b9423884a52c1c5b9dc573c6d702b0f9247a8
child 424602 eafc7904aedcb41d1180ba0c631b8b5c51218b4a
child 425613 49371cb65fd16ce84d4790141db0e3813b4275c4
push id32188
push usermaglione.k@gmail.com
push dateThu, 13 Oct 2016 01:14:44 +0000
reviewersochameau
bugs1309350
milestone52.0a1
Bug 1309350: Part 1 - Remove dead code and clean up cruft. r=ochameau I had to untangle a lot of this mess just to understand what was going on well enough to make changes. MozReview-Commit-ID: 2ygiK2ED1pX
addon-sdk/source/lib/toolkit/loader.js
addon-sdk/source/test/test-loader.js
addon-sdk/source/test/test-native-loader.js
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -31,31 +31,65 @@ const { loadSubScript } = Cc['@mozilla.o
 const { notifyObservers } = Cc['@mozilla.org/observer-service;1'].
                         getService(Ci.nsIObserverService);
 const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const { join: pathJoin, normalize, dirname } = Cu.import("resource://gre/modules/osfile/ospath_unix.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "XulApp", () => {
   let xulappURI = module.uri.replace("toolkit/loader.js",
-                                       "sdk/system/xul-app.jsm");
+                                     "sdk/system/xul-app.jsm");
   return Cu.import(xulappURI, {});
 });
 
 // Define some shortcuts.
 const bind = Function.call.bind(Function.bind);
 const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
-const define = Object.defineProperties;
 const prototypeOf = Object.getPrototypeOf;
-const create = Object.create;
-const keys = Object.keys;
 const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
                                 ...Object.getOwnPropertySymbols(x)];
 
-const NODE_MODULES = ["assert", "buffer_ieee754", "buffer", "child_process", "cluster", "console", "constants", "crypto", "_debugger", "dgram", "dns", "domain", "events", "freelist", "fs", "http", "https", "_linklist", "module", "net", "os", "path", "punycode", "querystring", "readline", "repl", "stream", "string_decoder", "sys", "timers", "tls", "tty", "url", "util", "vm", "zlib"];
+const NODE_MODULES = new Set([
+  "assert",
+  "buffer_ieee754",
+  "buffer",
+  "child_process",
+  "cluster",
+  "console",
+  "constants",
+  "crypto",
+  "_debugger",
+  "dgram",
+  "dns",
+  "domain",
+  "events",
+  "freelist",
+  "fs",
+  "http",
+  "https",
+  "_linklist",
+  "module",
+  "net",
+  "os",
+  "path",
+  "punycode",
+  "querystring",
+  "readline",
+  "repl",
+  "stream",
+  "string_decoder",
+  "sys",
+  "timers",
+  "tls",
+  "tty",
+  "url",
+  "util",
+  "vm",
+  "zlib",
+]);
 
 const COMPONENT_ERROR = '`Components` is not available in this context.\n' +
   'Functionality provided by Components may be available in an SDK\n' +
   'module: https://developer.mozilla.org/en-US/Add-ons/SDK \n\n' +
   'However, if you still need to import Components, you may use the\n' +
   '`chrome` module\'s properties for shortcuts to Component properties:\n\n' +
   'Shortcuts: \n' +
   '    Cc = Components' + '.classes \n' +
@@ -117,17 +151,17 @@ function iced(f) {
 // useful during loader bootstrap when other util modules can't be used &
 // thats only case where this export should be used.
 const override = iced(function override(target, source) {
   let properties = descriptor(target)
   let extension = descriptor(source || {})
   getOwnIdentifiers(extension).forEach(function(name) {
     properties[name] = extension[name];
   });
-  return define({}, properties);
+  return Object.defineProperties({}, properties);
 });
 Loader.override = override;
 
 function sourceURI(uri) { return String(uri).split(" -> ").pop(); }
 Loader.sourceURI = iced(sourceURI);
 
 function isntLoaderFrame(frame) { return frame.fileName !== module.uri }
 
@@ -188,17 +222,17 @@ function readURI(uri) {
   });
 
   stream.close();
 
   return data;
 }
 
 // Combines all arguments into a resolved, normalized path
-function join (...paths) {
+function join(...paths) {
   let joined = pathJoin(...paths);
   let resolved = normalize(joined);
 
   // OS.File `normalize` strips out any additional slashes breaking URIs like
   // `resource://`, `resource:///`, `chrome://` or `file:///`, so we work
   // around this putting back the slashes originally given, for such schemes.
   let re = /^(resource|file|chrome)(\:\/{1,3})([^\/])/;
   let matches = joined.match(re);
@@ -305,22 +339,22 @@ const load = iced(function load(loader, 
       loader.sharedGlobalBlocklist.indexOf(module.id) == -1) {
     // Create a new object in this sandbox, that will be used as
     // the scope object for this particular module
     sandbox = new loader.sharedGlobalSandbox.Object();
     // Inject all expected globals in the scope object
     getOwnIdentifiers(globals).forEach(function(name) {
       descriptors[name] = getOwnPropertyDescriptor(globals, name)
     });
-    define(sandbox, descriptors);
+    Object.defineProperties(sandbox, descriptors);
   }
   else {
     sandbox = Sandbox({
       name: module.uri,
-      prototype: create(globals, descriptors),
+      prototype: Object.create(globals, descriptors),
       wantXrays: false,
       wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : [],
       invisibleToDebugger: loader.invisibleToDebugger,
       metadata: {
         addonID: loader.id,
         URI: module.uri
       }
     });
@@ -354,26 +388,26 @@ const load = iced(function load(loader, 
     // it does.
     else if (frames[frames.length - 1].fileName !== file) {
       frames.push({ fileName: file, lineNumber: lineNumber, name: "" });
     }
 
     let prototype = typeof(error) === "object" ? error.constructor.prototype :
                     Error.prototype;
 
-    throw create(prototype, {
+    throw Object.create(prototype, {
       message: { value: message, writable: true, configurable: true },
       fileName: { value: fileName, writable: true, configurable: true },
       lineNumber: { value: lineNumber, writable: true, configurable: true },
       stack: { value: serializeStack(frames), writable: true, configurable: true },
       toString: { value: () => toString, writable: true, configurable: true },
     });
   }
 
-  if(loadModuleHook) {
+  if (loadModuleHook) {
     module = loadModuleHook(module, require);
   }
 
   if (loader.checkCompatibility) {
     let err = XulApp.incompatibility(module);
     if (err) {
       throw err;
     }
@@ -382,96 +416,159 @@ const load = iced(function load(loader, 
   if (module.exports && typeof(module.exports) === 'object')
     freeze(module.exports);
 
   return module;
 });
 Loader.load = load;
 
 // Utility function to normalize module `uri`s so they have `.js` extension.
-function normalizeExt (uri) {
+function normalizeExt(uri) {
   return isJSURI(uri) ? uri :
          isJSONURI(uri) ? uri :
          isJSMURI(uri) ? uri :
          uri + '.js';
 }
 
 // Strips `rootURI` from `string` -- used to remove absolute resourceURI
 // from a relative path
-function stripBase (rootURI, string) {
+function stripBase(rootURI, string) {
   return string.replace(rootURI, './');
 }
 
 // Utility function to join paths. In common case `base` is a
 // `requirer.uri` but in some cases it may be `baseURI`. In order to
 // avoid complexity we require `baseURI` with a trailing `/`.
 const resolve = iced(function resolve(id, base) {
-  if (!isRelative(id)) return id;
-  let basePaths = base.split('/');
-  // Pop the last element in the `base`, because it is from a
-  // relative file
-  // '../mod.js' from '/path/to/file.js' should resolve to '/path/mod.js'
-  basePaths.pop();
-  if (!basePaths.length)
+  if (!isRelative(id))
+    return id;
+
+  let baseDir = dirname(base);
+  if (!baseDir)
     return normalize(id);
-  let resolved = join(basePaths.join('/'), id);
+
+  let resolved = join(baseDir, id);
 
   // Joining and normalizing removes the './' from relative files.
   // We need to ensure the resolution still has the root
   if (isRelative(base))
     resolved = './' + resolved;
 
   return resolved;
 });
 Loader.resolve = resolve;
 
+// Attempts to load `path` and then `path.js`
+// Returns `path` with valid file, or `undefined` otherwise
+function resolveAsFile(path) {
+  let found;
+
+  // As per node's loader spec,
+  // we first should try and load 'path' (with no extension)
+  // before trying 'path.js'. We will not support this feature
+  // due to performance, but may add it if necessary for adoption.
+  try {
+    // Append '.js' to path name unless it's another support filetype
+    path = normalizeExt(path);
+    readURI(path);
+    found = path;
+  } catch (e) {}
+
+  return found;
+}
+
+// Attempts to load `path/package.json`'s `main` entry,
+// followed by `path/index.js`, or `undefined` otherwise
+function resolveAsDirectory(path) {
+  try {
+    // If `path/package.json` exists, parse the `main` entry
+    // and attempt to load that
+    let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
+    if (main != null) {
+      let tmpPath = join(path, main);
+      let found = resolveAsFile(tmpPath);
+      if (found)
+        return found
+    }
+  } catch (e) {}
+
+  try {
+    let tmpPath = path + '/index.js';
+    readURI(tmpPath);
+    return tmpPath;
+  } catch (e) {}
+
+  return null;
+}
+
+function resolveRelative(rootURI, modulesDir, id) {
+  let fullId = join(rootURI, modulesDir, id);
+  let resolvedPath;
+
+  if ((resolvedPath = resolveAsFile(fullId)))
+    return stripBase(rootURI, resolvedPath);
+
+  if ((resolvedPath = resolveAsDirectory(fullId)))
+    return stripBase(rootURI, resolvedPath);
+
+  return null;
+}
+
+// From `resolve` module
+// https://github.com/substack/node-resolve/blob/master/lib/node-modules-paths.js
+function* getNodeModulePaths(start) {
+  // Configurable in node -- do we need this to be configurable?
+  let moduleDir = 'node_modules';
+
+  let parts = start.split('/');
+  while (parts.length) {
+    let leaf = parts.pop();
+    if (leaf !== moduleDir)
+      yield join(...parts, leaf, moduleDir);
+  }
+
+  yield moduleDir;
+}
+
 // Node-style module lookup
 // Takes an id and path and attempts to load a file using node's resolving
 // algorithm.
 // `id` should already be resolved relatively at this point.
 // http://nodejs.org/api/modules.html#modules_all_together
 const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
   // Resolve again
   id = Loader.resolve(id, requirer);
 
   // If this is already an absolute URI then there is no resolution to do
   if (isAbsoluteURI(id))
-    return void 0;
+    return null;
 
   // we assume that extensions are correct, i.e., a directory doesnt't have '.js'
   // and a js file isn't named 'file.json.js'
-  let fullId = join(rootURI, id);
   let resolvedPath;
 
-  if ((resolvedPath = loadAsFile(fullId)))
-    return stripBase(rootURI, resolvedPath);
-
-  if ((resolvedPath = loadAsDirectory(fullId)))
-    return stripBase(rootURI, resolvedPath);
+  if ((resolvedPath = resolveRelative(rootURI, "", id)))
+    return resolvedPath;
 
   // If the requirer is an absolute URI then the node module resolution below
   // won't work correctly as we prefix everything with rootURI
   if (isAbsoluteURI(requirer))
-    return void 0;
+    return null;
 
   // If manifest has dependencies, attempt to look up node modules
   // in the `dependencies` list
-  let dirs = getNodeModulePaths(dirname(requirer)).map(dir => join(rootURI, dir, id));
-  for (let i = 0; i < dirs.length; i++) {
-    if ((resolvedPath = loadAsFile(dirs[i])))
-      return stripBase(rootURI, resolvedPath);
-
-    if ((resolvedPath = loadAsDirectory(dirs[i])))
-      return stripBase(rootURI, resolvedPath);
+  for (let modulesDir of getNodeModulePaths(dirname(requirer))) {
+    if ((resolvedPath = resolveRelative(rootURI, modulesDir, id)))
+      return resolvedPath;
   }
 
   // We would not find lookup for things like `sdk/tabs`, as that's part of
   // the alias mapping. If during `generateMap`, the runtime lookup resolves
   // with `resolveURI` -- if during runtime, then `resolve` will throw.
-  return void 0;
+  return null;
 });
 
 // String (`${rootURI}:${requirer}:${id}`) -> resolvedPath
 Loader.nodeResolverCache = new Map();
 
 const nodeResolveWithCache = iced(function cacheNodeResolutions(id, requirer, { rootURI }) {
   // Compute the cache key based on current arguments.
   let cacheKey = `${rootURI || ""}:${requirer}:${id}`;
@@ -483,127 +580,43 @@ const nodeResolveWithCache = iced(functi
 
   // Resolve and cache if it is not in the cache yet.
   let result = nodeResolve(id, requirer, { rootURI });
   Loader.nodeResolverCache.set(cacheKey, result);
   return result;
 });
 Loader.nodeResolve = nodeResolveWithCache;
 
-// Attempts to load `path` and then `path.js`
-// Returns `path` with valid file, or `undefined` otherwise
-function loadAsFile (path) {
-  let found;
-
-  // As per node's loader spec,
-  // we first should try and load 'path' (with no extension)
-  // before trying 'path.js'. We will not support this feature
-  // due to performance, but may add it if necessary for adoption.
-  try {
-    // Append '.js' to path name unless it's another support filetype
-    path = normalizeExt(path);
-    readURI(path);
-    found = path;
-  } catch (e) {}
-
-  return found;
-}
-
-// Attempts to load `path/package.json`'s `main` entry,
-// followed by `path/index.js`, or `undefined` otherwise
-function loadAsDirectory (path) {
-  try {
-    // If `path/package.json` exists, parse the `main` entry
-    // and attempt to load that
-    let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
-    if (main != null) {
-      let tmpPath = join(path, main);
-      let found = loadAsFile(tmpPath);
-      if (found)
-        return found
-    }
-    try {
-      let tmpPath = path + '/index.js';
-      readURI(tmpPath);
-      return tmpPath;
-    } catch (e) {}
-  } catch (e) {
-    try {
-      let tmpPath = path + '/index.js';
-      readURI(tmpPath);
-      return tmpPath;
-    } catch (e) {}
-  }
-  return void 0;
-}
-
-// From `resolve` module
-// https://github.com/substack/node-resolve/blob/master/lib/node-modules-paths.js
-function getNodeModulePaths (start) {
-  // Configurable in node -- do we need this to be configurable?
-  let moduleDir = 'node_modules';
-
-  let parts = start.split('/');
-  let dirs = [];
-  for (let i = parts.length - 1; i >= 0; i--) {
-    if (parts[i] === moduleDir) continue;
-    let dir = join(parts.slice(0, i + 1).join('/'), moduleDir);
-    dirs.push(dir);
-  }
-  dirs.push(moduleDir);
-  return dirs;
-}
-
-
-function addTrailingSlash (path) {
-  return !path ? null : !path.endsWith('/') ? path + '/' : path;
-}
-
-// Utility function to determine of module id `name` is a built in
-// module in node (fs, path, etc.);
-function isNodeModule (name) {
-  return !!~NODE_MODULES.indexOf(name);
-}
-
-// Make mapping array that is sorted from longest path to shortest path
-// to allow overlays. Used by `resolveURI`, returns an array
-function sortPaths (paths) {
-  return keys(paths).
-    sort((a, b) => (b.length - a.length)).
-    map((path) => [ path, paths[path] ]);
+function addTrailingSlash(path) {
+  return path.replace(/\/*$/, "/");
 }
 
 const resolveURI = iced(function resolveURI(id, mapping) {
-  let count = mapping.length, index = 0;
-
   // Do not resolve if already a resource URI
-  if (isAbsoluteURI(id)) return normalizeExt(id);
+  if (isAbsoluteURI(id))
+    return normalizeExt(id);
 
-  while (index < count) {
-    let [ path, uri ] = mapping[index++];
-
+  for (let [path, uri] of mapping) {
     // Strip off any trailing slashes to make comparisons simpler
-    let stripped = path.endsWith('/') ? path.slice(0, -1) : path;
+    let stripped = path.replace(/\/+$/, "");
 
     // We only want to match path segments explicitly. Examples:
     // * "foo/bar" matches for "foo/bar"
     // * "foo/bar" matches for "foo/bar/baz"
     // * "foo/bar" does not match for "foo/bar-1"
     // * "foo/bar/" does not match for "foo/bar"
     // * "foo/bar/" matches for "foo/bar/baz"
     //
     // Check for an empty path, an exact match, or a substring match
     // with the next character being a forward slash.
-    if(stripped === "" ||
-       (id.indexOf(stripped) === 0 &&
-        (id.length === path.length || id[stripped.length] === '/'))) {
+    if(stripped === "" || id === stripped || id.startsWith(stripped + "/")) {
       return normalizeExt(id.replace(path, uri));
     }
   }
-  return void 0; // otherwise we raise a warning, see bug 910304
+  return null;
 });
 Loader.resolveURI = resolveURI;
 
 // Creates version of `require` that will be exposed to the given `module`
 // in the context of the given `loader`. Each module gets own limited copy
 // of `require` that is allowed to load only a modules that are associated
 // with it during link time.
 const Require = iced(function Require(loader, requirer) {
@@ -699,41 +712,38 @@ const Require = iced(function Require(lo
       // immediately resolve the node-style mapping.
       // TODO: write more tests for this use case
       if (requireMap && requireMap[requirer.id])
         requirement = requireMap[requirer.id][id];
 
       let { overrides } = manifest.jetpack;
       for (let key in overrides) {
         // ignore any overrides using relative keys
-        if (/^[\.\/]/.test(key)) {
+        if (/^[.\/]/.test(key)) {
           continue;
         }
 
         // If the override is for x -> y,
         // then using require("x/lib/z") to get reqire("y/lib/z")
         // should also work
-        if (id == key || (id.substr(0, key.length + 1) == (key + "/"))) {
+        if (id == key || id.startsWith(key + "/")) {
           id = overrides[key] + id.substr(key.length);
-          id = id.replace(/^[\.\/]+/, "./");
-          if (id.substr(0, 2) == "./") {
-            id = "" + id.substr(2);
-          }
+          id = id.replace(/^[.\/]+/, "");
         }
       }
 
       // For native modules, we want to check if it's a module specified
       // in 'modules', like `chrome`, or `@loader` -- if it exists,
       // just set the uri to skip resolution
       if (!requirement && modules[id])
         uri = requirement = id;
 
       // If no requireMap was provided, or resolution not found in
       // the requireMap, and not a npm dependency, attempt a runtime lookup
-      if (!requirement && !isNodeModule(id)) {
+      if (!requirement && !NODE_MODULES.has(id)) {
         // If `isNative` defined, this is using the new, native-style
         // loader, not cuddlefish, so lets resolve using node's algorithm
         // and get back a path that needs to be resolved via paths mapping
         // in `resolveURI`
         requirement = loaderResolve(id, requirer.id, {
           manifest: manifest,
           rootURI: rootURI
         });
@@ -742,19 +752,22 @@ const Require = iced(function Require(lo
       // If not found in the map, not a node module, and wasn't able to be
       // looked up, it's something
       // found in the paths most likely, like `sdk/tabs`, which should
       // be resolved relatively if needed using traditional resolve
       if (!requirement) {
         requirement = isRelative(id) ? Loader.resolve(id, requirer.id) : id;
       }
     }
-    else {
+    else if (requirer) {
       // Resolve `id` to its requirer if it's relative.
-      requirement = requirer ? loaderResolve(id, requirer.id) : id;
+      requirement = loaderResolve(id, requirer.id);
+    }
+    else {
+      requirement = id;
     }
 
     // Resolves `uri` of module using loaders resolve function.
     uri = uri || resolveURI(requirement, mapping);
 
     // Throw if `uri` can not be resolved.
     if (!uri) {
       throw Error('Module: Can not resolve "' + id + '" module required by ' +
@@ -785,19 +798,19 @@ const main = iced(function main(loader, 
   let module = loader.main = loader.modules[uri] = Module(id, uri);
   return loader.load(loader, module).exports;
 });
 Loader.main = main;
 
 // Makes module object that is made available to CommonJS modules when they
 // are evaluated, along with `exports` and `require`.
 const Module = iced(function Module(id, uri) {
-  return create(null, {
+  return Object.create(null, {
     id: { enumerable: true, value: id },
-    exports: { enumerable: true, writable: true, value: create(null),
+    exports: { enumerable: true, writable: true, value: Object.create(null),
                configurable: true },
     uri: { value: uri }
   });
 });
 Loader.Module = Module;
 
 // Takes `loader`, and unload `reason` string and notifies all observers that
 // they should cleanup after them-self.
@@ -873,34 +886,38 @@ function Loader(options) {
     manifest.jetpack.overrides = {};
   }
 
   // We create an identity object that will be dispatched on an unload
   // event as subject. This way unload listeners will be able to assert
   // which loader is unloaded. Please note that we intentionally don't
   // use `loader` as subject to prevent a loader access leakage through
   // observer notifications.
-  let destructor = freeze(create(null));
+  let destructor = freeze(Object.create(null));
 
-  let mapping = sortPaths(paths);
+  // Make mapping array that is sorted from longest path to shortest path.
+  let mapping = Object.keys(paths)
+                      .sort((a, b) => b.length - a.length)
+                      .map(path => [path, paths[path]]);
 
   // Define pseudo modules.
   modules = override({
     '@loader/unload': destructor,
     '@loader/options': options,
     'chrome': { Cc: Cc, Ci: Ci, Cu: Cu, Cr: Cr, Cm: Cm,
                 CC: bind(CC, Components), components: Components,
                 // `ChromeWorker` has to be inject in loader global scope.
                 // It is done by bootstrap.js:loadSandbox for the SDK.
                 ChromeWorker: ChromeWorker
     }
   }, modules);
 
   const builtinModuleExports = modules;
-  modules = keys(modules).reduce(function(result, id) {
+  modules = {};
+  for (let id of Object.keys(builtinModuleExports)) {
     // We resolve `uri` from `id` since modules are cached by `uri`.
     let uri = resolveURI(id, mapping);
     // In native loader, the mapping will not contain values for
     // pseudomodules -- store them as their ID rather than the URI
     if (isNative && !uri)
       uri = id;
     let module = Module(id, uri);
 
@@ -908,19 +925,18 @@ function Loader(options) {
     // allow them to be loaded lazily.
     Object.defineProperty(module, "exports", {
       enumerable: true,
       get: function() {
         return builtinModuleExports[id];
       }
     });
 
-    result[uri] = freeze(module);
-    return result;
-  }, {});
+    modules[uri] = freeze(module);
+  }
 
   let sharedGlobalSandbox;
   if (sharedGlobal) {
     // Create the unique sandbox we will be using for all modules,
     // so that we prevent creating a new comportment per module.
     // The side effect is that all modules will share the same
     // global objects.
     sharedGlobalSandbox = Sandbox({
@@ -976,156 +992,29 @@ function Loader(options) {
 
   if (isNative) {
     returnObj.isNative = { enumerable: false, value: true };
     returnObj.manifest = { enumerable: false, value: manifest };
     returnObj.requireMap = { enumerable: false, value: requireMap };
     returnObj.rootURI = { enumerable: false, value: addTrailingSlash(rootURI) };
   }
 
-  return freeze(create(null, returnObj));
+  return freeze(Object.create(null, returnObj));
 };
 Loader.Loader = Loader;
 
-var isJSONURI = uri => uri.substr(-5) === '.json';
-var isJSMURI = uri => uri.substr(-4) === '.jsm';
-var isJSURI = uri => uri.substr(-3) === '.js';
-var isAbsoluteURI = uri => uri.indexOf("resource://") >= 0 ||
-                           uri.indexOf("chrome://") >= 0 ||
-                           uri.indexOf("file://") >= 0
-var isRelative = id => id[0] === '.'
-
-const generateMap = iced(function generateMap(options, callback) {
-  let { rootURI, resolve, paths } = override({
-    paths: {},
-    resolve: Loader.nodeResolve
-  }, options);
-
-  rootURI = addTrailingSlash(rootURI);
-
-  let manifest;
-  let manifestURI = join(rootURI, 'package.json');
-
-  if (rootURI)
-    manifest = JSON.parse(readURI(manifestURI));
-  else
-    throw new Error('No `rootURI` given to generate map');
-
-  let main = getManifestMain(manifest);
-
-  findAllModuleIncludes(main, {
-    resolve: resolve,
-    manifest: manifest,
-    rootURI: rootURI
-  }, {}, callback);
-
-});
-Loader.generateMap = generateMap;
+var isJSONURI = uri => uri.endsWith('.json');
+var isJSMURI = uri => uri.endsWith('.jsm');
+var isJSURI = uri => uri.endsWith('.js');
+var isAbsoluteURI = uri => uri.startsWith("resource://") ||
+                           uri.startsWith("chrome://") ||
+                           uri.startsWith("file://");
+var isRelative = id => id.startsWith(".");
 
 // Default `main` entry to './index.js' and ensure is relative,
 // since node allows 'lib/index.js' without relative `./`
-function getManifestMain (manifest) {
+function getManifestMain(manifest) {
   let main = manifest.main || './index.js';
   return isRelative(main) ? main : './' + main;
 }
 
-function findAllModuleIncludes (uri, options, results, callback) {
-  let { resolve, manifest, rootURI } = options;
-  results = results || {};
-
-  // Abort if JSON or JSM
-  if (isJSONURI(uri) || isJSMURI(uri)) {
-    callback(results);
-    return;
-  }
-
-  findModuleIncludes(join(rootURI, uri), modules => {
-    // If no modules are included in the file, just call callback immediately
-    if (!modules.length) {
-      callback(results);
-      return;
-    }
-
-    results[uri] = modules.reduce((agg, mod) => {
-      let resolved = resolve(mod, uri, { manifest: manifest, rootURI: rootURI });
-
-      // If resolution found, store the resolution; otherwise,
-      // skip storing it as runtime lookup will handle this
-      if (!resolved)
-        return agg;
-      agg[mod] = resolved;
-      return agg;
-    }, {});
-
-    let includes = keys(results[uri]);
-    let count = 0;
-    let subcallback = () => { if (++count >= includes.length) callback(results) };
-    includes.map(id => {
-      let moduleURI = results[uri][id];
-      if (!results[moduleURI])
-        findAllModuleIncludes(moduleURI, options, results, subcallback);
-      else
-        subcallback();
-    });
-  });
-}
-
-// From Substack's detector
-// https://github.com/substack/node-detective
-//
-// Given a resource URI or source, return an array of strings passed into
-// the require statements from the source
-function findModuleIncludes (uri, callback) {
-  let src = isAbsoluteURI(uri) ? readURI(uri) : uri;
-  let modules = [];
-
-  walk(src, function (node) {
-    if (isRequire(node))
-      modules.push(node.arguments[0].value);
-  });
-
-  callback(modules);
-}
-
-function walk (src, callback) {
-  // Import Reflect.jsm from here to prevent loading it until someone uses it
-  let { Reflect } = Cu.import("resource://gre/modules/reflect.jsm", {});
-  let nodes = Reflect.parse(src);
-  traverse(nodes, callback);
-}
-
-function traverse (node, cb) {
-  if (Array.isArray(node)) {
-    node.map(x => {
-      if (x != null) {
-        x.parent = node;
-        traverse(x, cb);
-      }
-    });
-  }
-  else if (node && typeof node === 'object') {
-    cb(node);
-    keys(node).map(key => {
-      if (key === 'parent' || !node[key]) return;
-      if (typeof node[key] === "object")
-        node[key].parent = node;
-      traverse(node[key], cb);
-    });
-  }
-}
-
-// From Substack's detector
-// https://github.com/substack/node-detective
-// Check an AST node to see if its a require statement.
-// A modification added to only evaluate to true if it actually
-// has a value being passed in as an argument
-function isRequire (node) {
-  var c = node.callee;
-  return c
-    && node.type === 'CallExpression'
-    && c.type === 'Identifier'
-    && c.name === 'require'
-    && node.arguments.length
-   && node.arguments[0].type === 'Literal';
-}
-
 module.exports = iced(Loader);
 });
--- a/addon-sdk/source/test/test-loader.js
+++ b/addon-sdk/source/test/test-loader.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 var {
-  Loader, main, unload, parseStack, generateMap, resolve, join,
+  Loader, main, unload, parseStack, resolve, join,
   Require, Module
 } = require('toolkit/loader');
 var { readURI } = require('sdk/net/url');
 
 var root = module.uri.substr(0, module.uri.lastIndexOf('/'));
 
 const app = require('sdk/system/xul-app');
 
--- a/addon-sdk/source/test/test-native-loader.js
+++ b/addon-sdk/source/test/test-native-loader.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 var {
-  Loader, main, unload, parseStack, generateMap, resolve, nodeResolve
+  Loader, main, unload, parseStack, resolve, nodeResolve
 } = require('toolkit/loader');
 var { readURI } = require('sdk/net/url');
 var { all } = require('sdk/core/promise');
 var testOptions = require('@test/options');
 
 var root = module.uri.substr(0, module.uri.lastIndexOf('/'))
 // The following adds Debugger constructor to the global namespace.
 const { Cu } = require('chrome');
@@ -65,29 +65,16 @@ exports['test nodeResolve'] = function (
 
 /*
 // TODO not working in current env
 exports['test bundle'] = function (assert, done) {
   loadAddon('/native-addons/native-addon-test/')
 };
 */
 
-exports['test generateMap()'] = function (assert, done) {
-  getJSON('/fixtures/native-addon-test/expectedmap.json').then(expected => {
-    generateMap({
-      rootURI: root + '/fixtures/native-addon-test/'
-    }, map => {
-      assert.deepEqual(map, expected, 'generateMap returns expected mappings');
-      assert.equal(map['./index.js']['./dir/a'], './dir/a.js',
-        'sanity check on correct mappings');
-      done();
-    });
-  }).then(null, (reason) => console.error(reason));
-};
-
 exports['test JSM loading'] = function (assert, done) {
   getJSON('/fixtures/jsm-package/package.json').then(manifest => {
     let rootURI = root + '/fixtures/jsm-package/';
     let loader = Loader({
       paths: makePaths(rootURI),
       rootURI: rootURI,
       manifest: manifest,
       isNative: true