Bug 835552 - Make load() be script-relative and read()/snarf() be cwd-relative.. r=njn
authorSteve Fink <sfink@mozilla.com>
Mon, 11 Mar 2013 15:36:16 -0700
changeset 131901 37474b43d0640e596b68fffb23e438353e07b745
parent 131900 015f4e8a16a8e1886fe2773697aa8b28d07a2fc9
child 131902 ae7e4da31bd7beae97d229039b63b2caea61af43
push idunknown
push userunknown
push dateunknown
reviewersnjn
bugs835552
milestone22.0a1
Bug 835552 - Make load() be script-relative and read()/snarf() be cwd-relative.. r=njn
js/src/jit-test/tests/basic/local.js
js/src/jit-test/tests/basic/testPaths.js
js/src/shell/js.cpp
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-1-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-2-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-3-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-4-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-5-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-6-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-7-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-8-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-function-length.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js
js/src/tests/ecma_5/Object/15.2.3.6-new-definition.js
js/src/tests/ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
js/src/tests/ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
js/src/tests/ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
js/src/tests/ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
toolkit/components/aboutmemory/tools/diff-memory-reports.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/local.js
@@ -0,0 +1,3 @@
+// A file in the same directory as testPaths.js
+
+x = 'local';
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testPaths.js
@@ -0,0 +1,51 @@
+// load() should resolve paths relative to the current script. That's easily
+// tested. snarf() aka read() should resolve paths relative to the current
+// working directory, which is harder to test because the shell doesn't really
+// have any (portable) notion of the current directory (and it can't create
+// files to enforce an expected layout.)
+
+loaded = {}
+snarfed = {}
+relatived = {}
+for (let f of ['local.js', '../basic/local.js', 'Y.js']) {
+  try {
+    load(f);
+    loaded[f] = true;
+  } catch(e) {
+    loaded[f] = !/can't open/.test(e);
+  }
+
+  try {
+    snarf(f);
+    snarfed[f] = true;
+  } catch(e) {
+    snarfed[f] = !/can't open/.test(e);
+  }
+
+  try {
+    readRelativeToScript(f);
+    relatived[f] = true;
+  } catch(e) {
+    relatived[f] = !/can't open/.test(e);
+  }
+}
+
+// local.js in the same dir as this script, so should be found by load() but
+// not snarf() -- unless you happen to be in that directory
+assertEq(loaded['local.js'], true);
+assertEq(loaded['../basic/local.js'], true);
+assertEq(relatived['local.js'], true);
+assertEq(relatived['../basic/local.js'], true);
+if (('PWD' in environment) && !(/test.*[\/\\]basic[\/\\]/.test(environment['PWD']))) {
+  assertEq(snarfed['local.js'], false);
+  assertEq(snarfed['../basic/local.js'], false);
+}
+
+// Y.js is in the root of the objdir, where |make check| is normally
+// run from.
+assertEq(loaded['Y.js'], false);
+assertEq(relatived['Y.js'], false);
+if (!snarfed['Y.js']) {
+  print("WARNING: expected to be able to find Y.js in current directory\n");
+  print("(not failing because it depends on where this test was run from)\n");
+}
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -66,17 +66,22 @@
 #include <sys/wait.h>
 #endif
 
 #if defined(XP_WIN) || defined(XP_OS2)
 #include <io.h>     /* for isatty() */
 #endif
 
 #ifdef XP_WIN
-#include "jswin.h"
+# include <io.h>
+# include <direct.h>
+# include "jswin.h"
+# define PATH_MAX (MAX_PATH > _MAX_DIR ? MAX_PATH : _MAX_DIR)
+#else
+# include <libgen.h>
 #endif
 
 #if JS_TRACE_LOGGING
 #include "TraceLogging.h"
 #endif
 
 using namespace js;
 using namespace js::cli;
@@ -670,16 +675,91 @@ Version(JSContext *cx, unsigned argc, js
 static JSBool
 RevertVersion(JSContext *cx, unsigned argc, jsval *vp)
 {
     js_RevertVersion(cx);
     JS_SET_RVAL(cx, vp, UndefinedValue());
     return true;
 }
 
+static JSScript *
+GetTopScript(JSContext *cx)
+{
+    RootedScript script(cx);
+    JS_DescribeScriptedCaller(cx, script.address(), NULL);
+    return script;
+}
+
+/*
+ * Resolve a (possibly) relative filename to an absolute path. If
+ * |scriptRelative| is true, then the result will be relative to the directory
+ * containing the currently-running script, or the current working directory if
+ * the currently-running script is "-e" (namely, you're using it from the
+ * command line.) Otherwise, it will be relative to the current working
+ * directory.
+ */
+static JSString *
+ResolvePath(JSContext *cx, HandleString filenameStr, bool scriptRelative)
+{
+    JSAutoByteString filename(cx, filenameStr);
+    if (!filename)
+        return NULL;
+
+    const char *pathname = filename.ptr();
+    if (pathname[0] == '/')
+        return filenameStr;
+#ifdef XP_WIN
+    // Various forms of absolute paths per http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
+    // "\..."
+    if (pathname[0] == '\\')
+        return filenameStr;
+    // "C:\..."
+    if (strlen(pathname) > 3 && isalpha(pathname[0]) && pathname[1] == ':' && pathname[2] == '\\')
+        return filenameStr;
+    // "\\..."
+    if (strlen(pathname) > 2 && pathname[1] == '\\' && pathname[2] == '\\')
+        return filenameStr;
+#endif
+
+    /* Get the currently executing script's name. */
+    RootedScript script(cx, GetTopScript(cx));
+    JS_ASSERT(script && script->filename());
+    if (strcmp(script->filename(), "-e") == 0 || strcmp(script->filename(), "typein") == 0)
+        scriptRelative = false;
+
+    static char buffer[PATH_MAX+1];
+    if (scriptRelative) {
+#ifdef XP_WIN
+        // The docs say it can return EINVAL, but the compiler says it's void
+        _splitpath(script->filename(), NULL, buffer, NULL, NULL);
+#else
+        strncpy(buffer, script->filename(), PATH_MAX+1);
+        if (buffer[PATH_MAX] != '\0')
+            return NULL;
+
+        // dirname(buffer) might return buffer, or it might return a
+        // statically-allocated string
+        memmove(buffer, dirname(buffer), strlen(buffer) + 1);
+#endif
+    } else {
+        const char *cwd = getcwd(buffer, PATH_MAX);
+        if (!cwd)
+            return NULL;
+        strcpy(buffer, cwd);
+    }
+
+    size_t len = strlen(buffer);
+    buffer[len] = '/';
+    strncpy(buffer + len + 1, pathname, sizeof(buffer) - (len+1));
+    if (buffer[PATH_MAX] != '\0')
+        return NULL;
+
+    return JS_NewStringCopyZ(cx, buffer);
+}
+
 static JSBool
 Options(JSContext *cx, unsigned argc, jsval *vp)
 {
     uint32_t optset, flag;
     JSString *str;
     char *names;
     bool found;
 
@@ -721,28 +801,31 @@ Options(JSContext *cx, unsigned argc, js
     free(names);
     if (!str)
         return false;
     JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
     return true;
 }
 
 static JSBool
-Load(JSContext *cx, unsigned argc, jsval *vp)
+LoadScript(JSContext *cx, unsigned argc, jsval *vp, bool scriptRelative)
 {
     RootedObject thisobj(cx, JS_THIS_OBJECT(cx, vp));
     if (!thisobj)
         return false;
 
     jsval *argv = JS_ARGV(cx, vp);
+    RootedString str(cx);
     for (unsigned i = 0; i < argc; i++) {
-        JSString *str = JS_ValueToString(cx, argv[i]);
+        str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return false;
-        argv[i] = STRING_TO_JSVAL(str);
+        str = ResolvePath(cx, str, scriptRelative);
+        if (!str)
+            return false;
         JSAutoByteString filename(cx, str);
         if (!filename)
             return false;
         errno = 0;
         CompileOptions opts(cx);
         opts.setUTF8(true).setCompileAndGo(true).setNoScriptRval(true);
         if ((compileOnly && !Compile(cx, thisobj, opts, filename.ptr())) ||
             !Evaluate(cx, thisobj, opts, filename.ptr(), NULL))
@@ -750,16 +833,28 @@ Load(JSContext *cx, unsigned argc, jsval
             return false;
         }
     }
 
     JS_SET_RVAL(cx, vp, UndefinedValue());
     return true;
 }
 
+static JSBool
+Load(JSContext *cx, unsigned argc, jsval *vp)
+{
+    return LoadScript(cx, argc, vp, true);
+}
+
+static JSBool
+LoadScriptRelativeToCwd(JSContext *cx, unsigned argc, jsval *vp)
+{
+    return LoadScript(cx, argc, vp, false);
+}
+
 class AutoNewContext
 {
   private:
     JSContext *oldcx;
     JSContext *newcx;
     Maybe<JSAutoRequest> newRequest;
 
     AutoNewContext(const AutoNewContext &) MOZ_DELETE;
@@ -1351,24 +1446,16 @@ SetDebug(JSContext *cx, unsigned argc, j
      */
 
     bool ok = !!JS_SetDebugMode(cx, JSVAL_TO_BOOLEAN(argv[0]));
     if (ok)
         JS_SET_RVAL(cx, vp, BooleanValue(true));
     return ok;
 }
 
-static RawScript
-GetTopScript(JSContext *cx)
-{
-    RootedScript script(cx);
-    JS_DescribeScriptedCaller(cx, script.address(), NULL);
-    return script;
-}
-
 static JSBool
 GetScriptAndPCArgs(JSContext *cx, unsigned argc, jsval *argv, MutableHandleScript scriptp,
                    int32_t *ip)
 {
     RootedScript script(cx, GetTopScript(cx));
     *ip = 0;
     if (argc != 0) {
         jsval v = argv[0];
@@ -2976,67 +3063,16 @@ Parent(JSContext *cx, unsigned argc, jsv
     if (parent) {
         if (JSObjectOp op = parent->getClass()->ext.outerObject)
             JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(op(cx, parent)));
     }
 
     return true;
 }
 
-#ifdef XP_UNIX
-
-#include <fcntl.h>
-#include <sys/stat.h>
-
-/*
- * Returns a JS_malloc'd string (that the caller needs to JS_free)
- * containing the directory (non-leaf) part of |from| prepended to |leaf|.
- * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf.
- * Returns NULL to indicate an error.
- */
-static char *
-MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf)
-{
-    size_t dirlen;
-    char *dir;
-    const char *slash = NULL, *cp;
-
-    if (*leaf == '/') {
-        /* We were given an absolute pathname. */
-        return JS_strdup(cx, leaf);
-    }
-
-    cp = from;
-    while (*cp) {
-        if (*cp == '/') {
-            slash = cp;
-        }
-
-        ++cp;
-    }
-
-    if (!slash) {
-        /* We were given a leaf or |from| was empty. */
-        return JS_strdup(cx, leaf);
-    }
-
-    /* Else, we were given a real pathname, return that + the leaf. */
-    dirlen = slash - from + 1;
-    dir = (char*) JS_malloc(cx, dirlen + strlen(leaf) + 1);
-    if (!dir)
-        return NULL;
-
-    strncpy(dir, from, dirlen);
-    strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */
-
-    return dir;
-}
-
-#endif // XP_UNIX
-
 static JSBool
 Compile(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (argc < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "compile", "0", "s");
         return false;
     }
@@ -3163,67 +3199,73 @@ struct FreeOnReturn
     }
 
     ~FreeOnReturn() {
         JS_free(cx, (void*)ptr);
     }
 };
 
 static JSBool
-Snarf(JSContext *cx, unsigned argc, jsval *vp)
+ReadFile(JSContext *cx, unsigned argc, jsval *vp, bool scriptRelative)
 {
-    JSString *str;
-
-    if (!argc)
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (args.length() < 1 || args.length() > 2) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+                             args.length() < 1 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
+                             "snarf");
         return false;
-
-    str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
-    if (!str)
+    }
+
+    if (!args[0].isString() || (args.length() == 2 && !args[1].isString())) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "snarf");
         return false;
+    }
+
+    RootedString givenPath(cx, args[0].toString());
+    RootedString str(cx, ResolvePath(cx, givenPath, scriptRelative));
     JSAutoByteString filename(cx, str);
     if (!filename)
         return false;
 
-    /* Get the currently executing script's name. */
-    RootedScript script(cx, GetTopScript(cx));
-    JS_ASSERT(script->filename());
-    const char *pathname = filename.ptr();
-#ifdef XP_UNIX
-    FreeOnReturn pnGuard(cx);
-    if (pathname[0] != '/') {
-        pathname = MakeAbsolutePathname(cx, script->filename(), pathname);
-        if (!pathname)
-            return false;
-        pnGuard.init(pathname);
-    }
-#endif
-
-    if (argc > 1) {
-        JSString *opt = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]);
+    if (args.length() > 1) {
+        JSString *opt = JS_ValueToString(cx, args[1]);
         if (!opt)
             return false;
         JSBool match;
         if (!JS_StringEqualsAscii(cx, opt, "binary", &match))
             return false;
         if (match) {
             JSObject *obj;
-            if (!(obj = FileAsTypedArray(cx, pathname)))
+            if (!(obj = FileAsTypedArray(cx, filename.ptr())))
                 return false;
             JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
             return true;
         }
     }
 
-    if (!(str = FileAsString(cx, pathname)))
+    if (!(str = FileAsString(cx, filename.ptr())))
         return false;
     JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
     return true;
 }
 
 static JSBool
+Snarf(JSContext *cx, unsigned argc, jsval *vp)
+{
+    return ReadFile(cx, argc, vp, false);
+}
+
+static JSBool
+ReadRelativeToScript(JSContext *cx, unsigned argc, jsval *vp)
+{
+    return ReadFile(cx, argc, vp, true);
+}
+
+static JSBool
 System(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSString *str;
 
     if (argc != 1) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS,
                              "system");
         return false;
@@ -3508,17 +3550,23 @@ static JSFunctionSpecWithHelp shell_func
 "  Revert previously set version number."),
 
     JS_FN_HELP("options", Options, 0, 0,
 "options([option ...])",
 "  Get or toggle JavaScript options."),
 
     JS_FN_HELP("load", Load, 1, 0,
 "load(['foo.js' ...])",
-"  Load files named by string arguments."),
+"  Load files named by string arguments. Filename is relative to the\n"
+"      script calling the load()."),
+
+    JS_FN_HELP("loadRelativeToCwd", LoadScriptRelativeToCwd, 1, 0,
+"loadRelativeToCwd(['foo.js' ...])",
+"  Load files named by string arguments. Filename is relative to the\n"
+"      current working directory."),
 
     JS_FN_HELP("evaluate", Evaluate, 2, 0,
 "evaluate(code[, options])",
 "  Evaluate code as though it were the contents of a file.\n"
 "  options is an optional object that may have these properties:\n"
 "      compileAndGo: use the compile-and-go compiler option (default: true)\n"
 "      noScriptRval: use the no-script-rval compiler option (default: false)\n"
 "      fileName: filename for error messages and debug info\n"
@@ -3709,23 +3757,29 @@ static JSFunctionSpecWithHelp shell_func
 #endif
 #ifdef JS_THREADSAFE
     JS_FN_HELP("sleep", Sleep_fn, 1, 0,
 "sleep(dt)",
 "  Sleep for dt seconds."),
 
 #endif
     JS_FN_HELP("snarf", Snarf, 1, 0,
-"snarf(filename)",
-"  Read filename into returned string."),
+"snarf(filename, [\"binary\"])",
+"  Read filename into returned string. Filename is relative to the current\n"
+               "  working directory."),
 
     JS_FN_HELP("read", Snarf, 1, 0,
-"read(filename)",
+"read(filename, [\"binary\"])",
 "  Synonym for snarf."),
 
+    JS_FN_HELP("readRelativeToScript", ReadRelativeToScript, 1, 0,
+"readRelativeToScript(filename, [\"binary\"])",
+"  Read filename into returned string. Filename is relative to the directory\n"
+               "  containing the current script."),
+
     JS_FN_HELP("system", System, 1, 0,
 "system(command)",
 "  Execute command on the current host, returning result code."),
 
     JS_FN_HELP("compile", Compile, 1, 0,
 "compile(code)",
 "  Compiles a string to bytecode, potentially throwing."),
 
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-1-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-1-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(1, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-2-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-2-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(2, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-3-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-3-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(3, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-4-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-4-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(4, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-5-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-5-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(5, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-6-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-6-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(6, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-7-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-7-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(7, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-8-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-8-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runDictionaryPropertyPresentTestsFraction(8, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-function-length.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-function-length.js
@@ -3,17 +3,17 @@
 // http://creativecommons.org/licenses/publicdomain/
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary = 'ES5 Object.defineProperty(O, P, Attributes): Function.length';
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runFunctionLengthTests();
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(1, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(2, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(3, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(4, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(5, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(6, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(7, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js
@@ -1,6 +1,6 @@
 // |reftest| skip-if(!xulRuntime.shell) -- uses shell load() function
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 runNonTerminalPropertyPresentTestsFraction(8, 8);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-new-definition.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-new-definition.js
@@ -3,17 +3,17 @@
 // http://creativecommons.org/licenses/publicdomain/
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary = 'ES5 Object.defineProperty(O, P, Attributes): new definition';
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runNotPresentTests();
--- a/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
@@ -7,17 +7,17 @@ var PART = 1, PARTS = 4;
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary =
   'ES5 Object.defineProperty(O, P, Attributes): redefinition ' +
   PART + ' of ' + PARTS;
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runPropertyPresentTestsFraction(PART, PARTS);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
@@ -7,17 +7,17 @@ var PART = 2, PARTS = 4;
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary =
   'ES5 Object.defineProperty(O, P, Attributes): redefinition ' +
   PART + ' of ' + PARTS;
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runPropertyPresentTestsFraction(PART, PARTS);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
@@ -7,17 +7,17 @@ var PART = 3, PARTS = 4;
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary =
   'ES5 Object.defineProperty(O, P, Attributes): redefinition ' +
   PART + ' of ' + PARTS;
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runPropertyPresentTestsFraction(PART, PARTS);
--- a/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
@@ -7,17 +7,17 @@ var PART = 4, PARTS = 4;
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 430133;
 var summary =
   'ES5 Object.defineProperty(O, P, Attributes): redefinition ' +
   PART + ' of ' + PARTS;
 
 print(BUGNUMBER + ": " + summary);
 
-load("ecma_5/Object/defineProperty-setup.js");
+load("defineProperty-setup.js");
 
 /**************
  * BEGIN TEST *
  **************/
 
 try
 {
   new TestRunner().runPropertyPresentTestsFraction(PART, PARTS);
--- a/toolkit/components/aboutmemory/tools/diff-memory-reports.js
+++ b/toolkit/components/aboutmemory/tools/diff-memory-reports.js
@@ -294,19 +294,16 @@ let kTestExpectedOutput =
 
 function matches(aA, aB)
 {
   return JSON.stringify(aA) === JSON.stringify(aB);
 }
 
 //---------------------------------------------------------------------------
 
-// XXX: note that read() looks for files relative to the path of the script,
-// not the path the script was invoked from.  Bug 835552 is open to fix this.
-
 let kUsageMsg =
 "Usage:\n\
 \n\
   diff-memory-reports.js <file1.json> <file2.json>\n\
 \n\
 or:\n\
 \n\
   diff-memory-reports.js --test\n\