Bug 801376 - OS.File loads symbols lazily;r=froydnj
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Tue, 22 Oct 2013 02:43:00 +0100
changeset 166709 b9c7369eb6159db08f0239e934e4a9b1f581af89
parent 166708 607ec7f406d0ecd26f0f284ec4a044688c3a7d8d
child 166710 ec99b2269e95ada1153d72fc4ce7ef75e37fccfc
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs801376
milestone27.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 801376 - OS.File loads symbols lazily;r=froydnj
toolkit/components/osfile/modules/osfile_shared_allthreads.jsm
toolkit/components/osfile/modules/osfile_unix_back.jsm
toolkit/components/osfile/modules/osfile_win_allthreads.jsm
toolkit/components/osfile/modules/osfile_win_back.jsm
toolkit/components/osfile/tests/xpcshell/test_unique.js
--- a/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm
+++ b/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm
@@ -36,16 +36,18 @@ let EXPORTED_SYMBOLS = [
   "LOG",
   "clone",
   "Config",
   "Constants",
   "Type",
   "HollowStructure",
   "OSError",
   "declareFFI",
+  "declareLazy",
+  "declareLazyFFI",
   "projectValue",
   "isTypedArray",
   "defineLazyGetter",
   "offsetBy",
   "OS" // Warning: this exported symbol will disappear
 ];
 
 ////////////////////// Configuration of OS.File
@@ -885,19 +887,17 @@ exports.HollowStructure = HollowStructur
  * library.
  * @param {ctypes.abi} abi The abi to use, or |null| for default.
  * @param {Type} returnType The type of values returned by the function.
  * @param {...Type} argTypes The type of arguments to the function.
  *
  * @return null if the function could not be defined (generally because
  * it does not exist), or a JavaScript wrapper performing the call to C
  * and any type conversion required.
- */// Note: Future versions will use a different implementation of this
-   // function on the main thread, osfile worker thread and regular worker
-   // thread
+ */
 let declareFFI = function declareFFI(lib, symbol, abi,
                                      returnType /*, argTypes ...*/) {
   LOG("Attempting to declare FFI ", symbol);
   // We guard agressively, to avoid any late surprise
   if (typeof symbol != "string") {
     throw new TypeError("declareFFI expects as first argument a string");
   }
   abi = abi || ctypes.default_abi;
@@ -936,16 +936,72 @@ let declareFFI = function declareFFI(lib
     // Note: Not being able to declare a function is normal.
     // Some functions are OS (or OS version)-specific.
     LOG("Could not declare function ", symbol, x);
     return null;
   }
 };
 exports.declareFFI = declareFFI;
 
+/**
+ * Define a lazy getter to a js-ctypes function using declareFFI.
+ *
+ * @param {object} The object containing the function as a field.
+ * @param {string} The name of the field containing the function.
+ * @param {ctypes.library} lib The ctypes library holding the function.
+ * @param {string} symbol The name of the function, as defined in the
+ * library.
+ * @param {ctypes.abi} abi The abi to use, or |null| for default.
+ * @param {Type} returnType The type of values returned by the function.
+ * @param {...Type} argTypes The type of arguments to the function.
+ */
+function declareLazyFFI(object, field, ...declareFFIArgs) {
+  Object.defineProperty(object, field, {
+    get: function() {
+      delete this[field];
+      let ffi = declareFFI(...declareFFIArgs);
+      if (ffi) {
+        return this[field] = ffi;
+      }
+      return undefined;
+    },
+    configurable: true
+  });
+}
+exports.declareLazyFFI = declareLazyFFI;
+
+/**
+ * Define a lazy getter to a js-ctypes function using ctypes method declare.
+ *
+ * @param {object} The object containing the function as a field.
+ * @param {string} The name of the field containing the function.
+ * @param {ctypes.library} lib The ctypes library holding the function.
+ * @param {string} symbol The name of the function, as defined in the
+ * library.
+ * @param {ctypes.abi} abi The abi to use, or |null| for default.
+ * @param {ctypes.CType} returnType The type of values returned by the function.
+ * @param {...ctypes.CType} argTypes The type of arguments to the function.
+ */
+function declareLazy(object, field, lib, ...declareArgs) {
+  Object.defineProperty(object, field, {
+    get: function() {
+      delete this[field];
+      try {
+        let ffi = lib.declare(...declareArgs);
+        return this[field] = ffi;
+      } catch (ex) {
+        // The symbol doesn't exist
+        return undefined;
+      }
+    },
+    configurable: true
+  });
+}
+exports.declareLazy = declareLazy;
+
 // A bogus array type used to perform pointer arithmetics
 let gOffsetByType;
 
 /**
  * Advance a pointer by a number of items.
  *
  * This method implements adding an integer to a pointer in C.
  *
--- a/toolkit/components/osfile/modules/osfile_unix_back.jsm
+++ b/toolkit/components/osfile/modules/osfile_unix_back.jsm
@@ -33,43 +33,44 @@
      // FIXME: Both |init| and |aDeclareFFI| are deprecated, we should remove them
      let init = function init(aDeclareFFI) {
        let declareFFI;
        if (aDeclareFFI) {
          declareFFI = aDeclareFFI.bind(null, libc);
        } else {
          declareFFI = SysAll.declareFFI;
        }
+       let declareLazyFFI = SharedAll.declareLazyFFI;
 
        // Initialize types that require additional OS-specific
        // support - either finalization or matching against
        // OS-specific constants.
        let Type = Object.create(SysAll.Type);
        let SysFile = exports.OS.Unix.File = { Type: Type };
 
        /**
         * A file descriptor.
         */
        Type.fd = Type.int.withName("fd");
        Type.fd.importFromC = function importFromC(fd_int) {
-         return ctypes.CDataFinalizer(fd_int, _close);
+         return ctypes.CDataFinalizer(fd_int, SysFile._close);
        };
 
 
        /**
         * A C integer holding -1 in case of error or a file descriptor
         * in case of success.
         */
        Type.negativeone_or_fd = Type.fd.withName("negativeone_or_fd");
        Type.negativeone_or_fd.importFromC =
          function importFromC(fd_int) {
            if (fd_int == -1) {
              return -1;
            }
-           return ctypes.CDataFinalizer(fd_int, _close);
+           return ctypes.CDataFinalizer(fd_int, SysFile._close);
          };
 
        /**
         * A C integer holding -1 in case of error or a meaningless value
         * in case of success.
         */
        Type.negativeone_or_nothing =
          Type.int.withName("negativeone_or_nothing");
@@ -191,34 +192,34 @@
        }
 
        Type.null_or_DIR_ptr =
          Type.DIR.out_ptr.withName("null_or_DIR*");
        Type.null_or_DIR_ptr.importFromC = function importFromC(dir) {
          if (dir == null || dir.isNull()) {
            return null;
          }
-         return ctypes.CDataFinalizer(dir, _close_dir);
+         return ctypes.CDataFinalizer(dir, SysFile._close_dir);
        };
 
        // Declare libc functions as functions of |OS.Unix.File|
 
        // Finalizer-related functions
-       let _close = SysFile._close =
-         libc.declare("close", ctypes.default_abi,
+       SharedAll.declareLazy(SysFile, "_close", libc,
+           "close", ctypes.default_abi,
                         /*return */ctypes.int,
                         /*fd*/     ctypes.int);
 
        SysFile.close = function close(fd) {
          // Detach the finalizer and call |_close|.
          return fd.dispose();
        };
 
-       let _close_dir =
-         libc.declare("closedir", ctypes.default_abi,
+       SharedAll.declareLazy(SysFile, "_close_dir", libc,
+                             "closedir", ctypes.default_abi,
                         /*return */ctypes.int,
                         /*dirp*/   Type.DIR.in_ptr.implementation);
 
        SysFile.closedir = function closedir(fd) {
          // Detach the finalizer and call |_close_dir|.
          return fd.dispose();
        };
 
@@ -227,314 +228,263 @@
          // We override the definition of free() on several platforms.
          let default_lib = libc;
          try {
            // On platforms for which we override free(), nspr defines
            // a special library name "a.out" that will resolve to the
            // correct implementation free().
            default_lib = ctypes.open("a.out");
 
-           SysFile.free =
-             default_lib.declare("free", ctypes.default_abi,
+           SharedAll.declareLazy(SysFile, "free", default_lib,
+             "free", ctypes.default_abi,
              /*return*/ ctypes.void_t,
              /*ptr*/    ctypes.voidptr_t);
 
          } catch (ex) {
            // We don't have an a.out library or a.out doesn't contain free.
            // Either way, use the ordinary libc free.
 
-           SysFile.free =
-             libc.declare("free", ctypes.default_abi,
+           SharedAll.declareLazy(SysFile, "free", libc,
+             "free", ctypes.default_abi,
              /*return*/ ctypes.void_t,
              /*ptr*/    ctypes.voidptr_t);
          }
       }
 
 
        // Other functions
-       SysFile.access =
-         declareFFI("access", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "access", libc, "access", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path,
                     /*mode*/   Type.int);
 
-       SysFile.chdir =
-         declareFFI("chdir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "chdir", libc, "chdir", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path);
 
-       SysFile.chmod =
-         declareFFI("chmod", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "chmod", libc, "chmod", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path,
                     /*mode*/   Type.mode_t);
 
-       SysFile.chown =
-         declareFFI("chown", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "chown", libc, "chown", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path,
                     /*uid*/    Type.uid_t,
                     /*gid*/    Type.gid_t);
 
-       SysFile.copyfile =
-         declareFFI("copyfile", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "copyfile", libc, "copyfile", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*source*/ Type.path,
                     /*dest*/   Type.path,
                     /*state*/  Type.void_t.in_ptr, // Ignored atm
                     /*flags*/  Type.uint32_t);
 
-       SysFile.dup =
-         declareFFI("dup", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "dup", libc, "dup", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_fd,
                     /*fd*/     Type.fd);
 
        if ("OSFILE_SIZEOF_DIR" in Const) {
          // On platforms for which |dirfd| is a macro
          SysFile.dirfd =
            function dirfd(DIRp) {
              return Type.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
            };
        } else {
          // On platforms for which |dirfd| is a function
-         SysFile.dirfd =
-           declareFFI("dirfd", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "dirfd", libc, "dirfd", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_fd,
                       /*dir*/    Type.DIR.in_ptr);
        }
 
-       SysFile.chdir =
-         declareFFI("chdir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "chdir", libc, "chdir", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path);
 
-       SysFile.fchdir =
-         declareFFI("fchdir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "fchdir", libc, "fchdir", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*fd*/     Type.fd);
 
-       SysFile.fchown =
-         declareFFI("fchown", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "fchown", libc, "fchown", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*fd*/     Type.fd,
                     /*uid_t*/  Type.uid_t,
                     /*gid_t*/  Type.gid_t);
 
-       SysFile.fsync =
-         declareFFI("fsync", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "fsync", libc, "fsync", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*fd*/     Type.fd);
 
-       SysFile.getcwd =
-         declareFFI("getcwd", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "getcwd", libc, "getcwd", ctypes.default_abi,
                     /*return*/ Type.out_path,
                     /*buf*/    Type.out_path,
                     /*size*/   Type.size_t);
 
-       SysFile.getwd =
-         declareFFI("getwd", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "getwd", libc, "getwd", ctypes.default_abi,
                     /*return*/ Type.out_path,
                     /*buf*/    Type.out_path);
 
        // Two variants of |getwd| which allocate the memory
        // dynamically.
 
        // Linux/Android version
-       SysFile.get_current_dir_name =
-         declareFFI("get_current_dir_name", ctypes.default_abi,
-                    /*return*/ Type.out_path.releaseWith(SysFile.free));
+       declareLazyFFI(SysFile,  "get_current_dir_name", libc,
+                      "get_current_dir_name", ctypes.default_abi,
+                      /*return*/ Type.out_path.releaseWith(SysFile.free));
 
        // MacOS/BSD version (will return NULL on Linux/Android)
-       SysFile.getwd_auto =
-         declareFFI("getwd", ctypes.default_abi,
-                    /*return*/ Type.out_path.releaseWith(SysFile.free),
-                    /*buf*/    Type.void_t.out_ptr);
+       declareLazyFFI(SysFile,  "getwd_auto", libc,
+                      "getwd", ctypes.default_abi,
+                      /*return*/ Type.out_path.releaseWith(SysFile.free),
+                      /*buf*/    Type.void_t.out_ptr);
 
-       SysFile.fdatasync =
-         declareFFI("fdatasync", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "fdatasync", libc,
+                      "fdatasync", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*fd*/     Type.fd); // Note: MacOS/BSD-specific
 
-       SysFile.ftruncate =
-         declareFFI("ftruncate", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "ftruncate", libc,
+                      "ftruncate", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*fd*/     Type.fd,
                     /*length*/ Type.off_t);
 
-       if (Const._DARWIN_FEATURE_64_BIT_INODE) {
-         SysFile.fstat =
-           declareFFI("fstat$INODE64", ctypes.default_abi,
-                      /*return*/ Type.negativeone_or_nothing,
-                      /*path*/   Type.fd,
-                      /*buf*/    Type.stat.out_ptr
-                     );
-       } else {
-         SysFile.fstat =
-           declareFFI("fstat", ctypes.default_abi,
-                      /*return*/ Type.negativeone_or_nothing,
-                      /*path*/   Type.fd,
-                      /*buf*/    Type.stat.out_ptr
-                     );
-       }
 
-       SysFile.lchown =
-         declareFFI("lchown", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "lchown", libc, "lchown", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/   Type.path,
                     /*uid_t*/  Type.uid_t,
                     /*gid_t*/  Type.gid_t);
 
-       SysFile.link =
-         declareFFI("link", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "link", libc, "link", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*source*/ Type.path,
                     /*dest*/   Type.path);
 
-       SysFile.lseek =
-         declareFFI("lseek", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "lseek", libc, "lseek", ctypes.default_abi,
                     /*return*/ Type.off_t,
                     /*fd*/     Type.fd,
                     /*offset*/ Type.off_t,
                     /*whence*/ Type.int);
 
-       SysFile.mkdir =
-         declareFFI("mkdir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "mkdir", libc, "mkdir", ctypes.default_abi,
                     /*return*/ Type.int,
                     /*path*/ Type.path,
                     /*mode*/ Type.int);
 
-       SysFile.mkstemp =
-         declareFFI("mkstemp", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "mkstemp", libc, "mkstemp", ctypes.default_abi,
                     /*return*/ Type.fd,
                     /*template*/Type.out_path);
 
-       SysFile.open =
-         declareFFI("open", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "open", libc, "open", ctypes.default_abi,
                     /*return*/Type.negativeone_or_fd,
                     /*path*/  Type.path,
                     /*oflags*/Type.int,
                     /*mode*/  Type.int);
 
-       SysFile.opendir =
-         declareFFI("opendir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "opendir", libc, "opendir", ctypes.default_abi,
                     /*return*/ Type.null_or_DIR_ptr,
                     /*path*/   Type.path);
 
-       SysFile.pread =
-         declareFFI("pread", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "pread", libc, "pread", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_ssize_t,
                     /*fd*/     Type.fd,
                     /*buf*/    Type.void_t.out_ptr,
                     /*nbytes*/ Type.size_t,
                     /*offset*/ Type.off_t);
 
-       SysFile.pwrite =
-         declareFFI("pwrite", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "pwrite", libc, "pwrite", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_ssize_t,
                     /*fd*/     Type.fd,
                     /*buf*/    Type.void_t.in_ptr,
                     /*nbytes*/ Type.size_t,
                     /*offset*/ Type.off_t);
 
-       SysFile.read =
-         declareFFI("read", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "read", libc, "read", ctypes.default_abi,
                     /*return*/Type.negativeone_or_ssize_t,
                     /*fd*/    Type.fd,
                     /*buf*/   Type.void_t.out_ptr,
                     /*nbytes*/Type.size_t);
 
-       SysFile.posix_fadvise =
-         declareFFI("posix_fadvise", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "posix_fadvise", libc, "posix_fadvise", ctypes.default_abi,
                     /*return*/ Type.int,
                     /*fd*/     Type.fd,
                     /*offset*/ Type.off_t,
                     /*len*/    Type.off_t,
                     /*advise*/ Type.int);
 
        if (Const._DARWIN_FEATURE_64_BIT_INODE) {
          // Special case for MacOS X 10.5+
          // Symbol name "readdir" still exists but is used for a
          // deprecated function that does not match the
          // constants of |Const|.
-         SysFile.readdir =
-           declareFFI("readdir$INODE64", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "readdir", libc, "readdir$INODE64", ctypes.default_abi,
                      /*return*/Type.null_or_dirent_ptr,
                       /*dir*/   Type.DIR.in_ptr); // For MacOS X
        } else {
-         SysFile.readdir =
-           declareFFI("readdir", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "readdir", libc, "readdir", ctypes.default_abi,
                       /*return*/Type.null_or_dirent_ptr,
                       /*dir*/   Type.DIR.in_ptr); // Other Unices
        }
 
-       SysFile.rename =
-         declareFFI("rename", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "rename", libc, "rename", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*old*/    Type.path,
                     /*new*/    Type.path);
 
-       SysFile.rmdir =
-         declareFFI("rmdir", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "rmdir", libc, "rmdir", ctypes.default_abi,
                     /*return*/ Type.int,
                     /*path*/   Type.path);
 
-       SysFile.splice =
-         declareFFI("splice", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "splice", libc, "splice", ctypes.default_abi,
                     /*return*/ Type.long,
                     /*fd_in*/  Type.fd,
                     /*off_in*/ Type.off_t.in_ptr,
                     /*fd_out*/ Type.fd,
                     /*off_out*/Type.off_t.in_ptr,
                     /*len*/    Type.size_t,
                     /*flags*/  Type.unsigned_int); // Linux/Android-specific
 
-       SysFile.symlink =
-         declareFFI("symlink", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "symlink", libc, "symlink", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*source*/ Type.path,
                     /*dest*/   Type.path);
 
-       SysFile.truncate =
-         declareFFI("truncate", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "truncate", libc, "truncate", ctypes.default_abi,
                     /*return*/Type.negativeone_or_nothing,
                     /*path*/  Type.path,
                     /*length*/ Type.off_t);
 
-       SysFile.unlink =
-         declareFFI("unlink", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "unlink", libc, "unlink", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_nothing,
                     /*path*/ Type.path);
 
-       SysFile.write =
-         declareFFI("write", ctypes.default_abi,
+       declareLazyFFI(SysFile,  "write", libc, "write", ctypes.default_abi,
                     /*return*/ Type.negativeone_or_ssize_t,
                     /*fd*/     Type.fd,
                     /*buf*/    Type.void_t.in_ptr,
                     /*nbytes*/ Type.size_t);
 
        // Weird cases that require special treatment
 
        // OSes use a variety of hacks to differentiate between
        // 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
        if (Const._DARWIN_FEATURE_64_BIT_INODE) {
          // MacOS X 64-bits
-         SysFile.stat =
-           declareFFI("stat$INODE64", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "stat", libc, "stat$INODE64", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*path*/   Type.path,
                       /*buf*/    Type.stat.out_ptr
                      );
-         SysFile.lstat =
-           declareFFI("lstat$INODE64", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "lstat", libc, "lstat$INODE64", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*path*/   Type.path,
                       /*buf*/    Type.stat.out_ptr
                      );
-         SysFile.fstat =
-           declareFFI("fstat$INODE64", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "fstat", libc, "fstat$INODE64", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*path*/   Type.fd,
                       /*buf*/    Type.stat.out_ptr
                      );
        } else if (Const._STAT_VER != undefined) {
          const ver = Const._STAT_VER;
          let xstat_name, lxstat_name, fxstat_name;
          if (OS.Constants.Sys.Name == "SunOS") {
@@ -544,85 +494,85 @@
            fxstat_name = "_fxstat";
          } else {
            // Linux, all widths
            xstat_name = "__xstat";
            lxstat_name = "__lxstat";
            fxstat_name = "__fxstat";
          }
 
-         let xstat =
-           declareFFI(xstat_name, ctypes.default_abi,
+         let Stat = {};
+         declareLazyFFI(Stat,  "xstat", libc, xstat_name, ctypes.default_abi,
                       /*return*/    Type.negativeone_or_nothing,
                       /*_stat_ver*/ Type.int,
                       /*path*/      Type.path,
                       /*buf*/       Type.stat.out_ptr);
-         let lxstat =
-           declareFFI(lxstat_name, ctypes.default_abi,
+         declareLazyFFI(Stat,  "lxstat", libc, lxstat_name, ctypes.default_abi,
                       /*return*/    Type.negativeone_or_nothing,
                       /*_stat_ver*/ Type.int,
                       /*path*/      Type.path,
                       /*buf*/       Type.stat.out_ptr);
-         let fxstat =
-           declareFFI(fxstat_name, ctypes.default_abi,
+         declareLazyFFI(Stat, "fxstat", libc,
+           fxstat_name, ctypes.default_abi,
                       /*return*/    Type.negativeone_or_nothing,
                       /*_stat_ver*/ Type.int,
                       /*fd*/        Type.fd,
                       /*buf*/       Type.stat.out_ptr);
 
+         
          SysFile.stat = function stat(path, buf) {
-           return xstat(ver, path, buf);
+           return Stat.xstat(ver, path, buf);
          };
-         SysFile.lstat = function stat(path, buf) {
-           return lxstat(ver, path, buf);
+
+         SysFile.lstat = function lstat(path, buf) {
+           return Stat.lxstat(ver, path, buf);
          };
-         SysFile.fstat = function stat(fd, buf) {
-           return fxstat(ver, fd, buf);
+
+         SysFile.fstat = function fstat(fd, buf) {
+           return Stat.fxstat(ver, fd, buf);
          };
        } else {
          // Mac OS X 32-bits, other Unix
-         SysFile.stat =
-           declareFFI("stat", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "stat", libc, "stat", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*path*/   Type.path,
                       /*buf*/    Type.stat.out_ptr
                      );
-         SysFile.lstat =
-           declareFFI("lstat", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "lstat", libc, "lstat", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*path*/   Type.path,
                       /*buf*/    Type.stat.out_ptr
                      );
-         SysFile.fstat =
-           declareFFI("fstat", ctypes.default_abi,
+         declareLazyFFI(SysFile,  "fstat", libc, "fstat", ctypes.default_abi,
                       /*return*/ Type.negativeone_or_nothing,
                       /*fd*/     Type.fd,
                       /*buf*/    Type.stat.out_ptr
                      );
        }
 
        // We cannot make a C array of CDataFinalizer, so
        // pipe cannot be directly defined as a C function.
 
-       let _pipe =
-         declareFFI("pipe", ctypes.default_abi,
-           /*return*/ Type.negativeone_or_nothing,
-           /*fds*/    new SharedAll.Type("two file descriptors",
+       let Pipe = {};
+       declareLazyFFI(Pipe, "_pipe", libc,
+         "pipe", ctypes.default_abi,
+         /*return*/ Type.negativeone_or_nothing,
+         /*fds*/    new SharedAll.Type("two file descriptors",
              ctypes.ArrayType(ctypes.int, 2)));
 
        // A shared per-thread buffer used to communicate with |pipe|
        let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
 
        SysFile.pipe = function pipe(array) {
-         let result = _pipe(_pipebuf);
+         let result = Pipe._pipe(_pipebuf);
          if (result == -1) {
            return result;
          }
-         array[0] = ctypes.CDataFinalizer(_pipebuf[0], _close);
-         array[1] = ctypes.CDataFinalizer(_pipebuf[1], _close);
+         array[0] = ctypes.CDataFinalizer(_pipebuf[0], SysFile._close);
+         array[1] = ctypes.CDataFinalizer(_pipebuf[1], SysFile._close);
          return result;
        };
      };
 
      exports.OS.Unix = {
        File: {
          _init: init
        }
--- a/toolkit/components/osfile/modules/osfile_win_allthreads.jsm
+++ b/toolkit/components/osfile/modules/osfile_win_allthreads.jsm
@@ -48,18 +48,21 @@ try {
   throw new Error("Could not open system library: " + ex.message);
 }
 exports.libc = libc;
 
 // Define declareFFI
 let declareFFI = SharedAll.declareFFI.bind(null, libc);
 exports.declareFFI = declareFFI;
 
+let Scope = {};
+
 // Define Error
-let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
+SharedAll.declareLazy(Scope, "FormatMessage", libc,
+  "FormatMessageW", ctypes.winapi_abi,
   /*return*/ ctypes.uint32_t,
   /*flags*/  ctypes.uint32_t,
   /*source*/ ctypes.voidptr_t,
   /*msgid*/  ctypes.uint32_t,
   /*langid*/ ctypes.uint32_t,
   /*buf*/    ctypes.jschar.ptr,
   /*size*/   ctypes.uint32_t,
   /*Arguments*/ctypes.voidptr_t
@@ -91,17 +94,17 @@ let FormatMessage = libc.declare("Format
 let OSError = function OSError(operation, lastError) {
   operation = operation || "unknown operation";
   SharedAll.OSError.call(this, operation);
   this.winLastError = lastError || ctypes.winLastError;
 };
 OSError.prototype = Object.create(SharedAll.OSError.prototype);
 OSError.prototype.toString = function toString() {
   let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
-  let result = FormatMessage(
+  let result = Scope.FormatMessage(
     Const.FORMAT_MESSAGE_FROM_SYSTEM |
     Const.FORMAT_MESSAGE_IGNORE_INSERTS,
     null,
     /* The error number */ this.winLastError,
     /* Default language */ 0,
     /* Output buffer*/     buf,
     /* Minimum size of buffer */ 1024,
     /* Format args*/       null
--- a/toolkit/components/osfile/modules/osfile_win_back.jsm
+++ b/toolkit/components/osfile/modules/osfile_win_back.jsm
@@ -49,16 +49,17 @@
      // FIXME: Both |init| and |aDeclareFFI| are deprecated, we should remove them
      let init = function init(aDeclareFFI) {
        let declareFFI;
        if (aDeclareFFI) {
          declareFFI = aDeclareFFI.bind(null, libc);
        } else {
          declareFFI = SysAll.declareFFI;
        }
+       let declareLazyFFI = SharedAll.declareLazyFFI;
 
        // Initialize types that require additional OS-specific
        // support - either finalization or matching against
        // OS-specific constants.
        let Type = Object.create(SysAll.Type);
        let SysFile = exports.OS.Win.File = { Type: Type };
 
        // Initialize types
@@ -82,24 +83,24 @@
          throw new Error("finalizeHANDLE should be implemented");
        };
        let INVALID_HANDLE = Const.INVALID_HANDLE_VALUE;
 
        Type.file_HANDLE = Type.HANDLE.withName("file HANDLE");
        SharedAll.defineLazyGetter(Type.file_HANDLE,
          "finalizeHANDLE",
          function() {
-           return _CloseHandle;
+           return SysFile._CloseHandle;
          });
 
        Type.find_HANDLE = Type.HANDLE.withName("find HANDLE");
        SharedAll.defineLazyGetter(Type.find_HANDLE,
          "finalizeHANDLE",
          function() {
-           return _FindClose;
+           return SysFile._FindClose;
          });
 
        Type.DWORD = Type.int32_t.withName("DWORD");
 
        /**
         * A C integer holding -1 in case of error or a positive integer
         * in case of success.
         */
@@ -168,170 +169,170 @@
                   { wHour:      ctypes.int16_t },
                   { wMinute:    ctypes.int16_t },
                   { wSecond:    ctypes.int16_t },
                   { wMilliSeconds: ctypes.int16_t }
                   ]));
 
        // Special case: these functions are used by the
        // finalizer
-       let _CloseHandle = SysFile._CloseHandle =
-         libc.declare("CloseHandle", ctypes.winapi_abi,
+       SharedAll.declareLazy(SysFile, "_CloseHandle", libc,
+                      "CloseHandle", ctypes.winapi_abi,
                         /*return */ctypes.bool,
                         /*handle*/ ctypes.voidptr_t);
 
        SysFile.CloseHandle = function(fd) {
          if (fd == INVALID_HANDLE) {
            return true;
          } else {
            return fd.dispose(); // Returns the value of |CloseHandle|.
          }
        };
 
-       let _FindClose =
-         libc.declare("FindClose", ctypes.winapi_abi,
+       SharedAll.declareLazy(SysFile, "_FindClose", libc,
+                      "FindClose", ctypes.winapi_abi,
                         /*return */ctypes.bool,
                         /*handle*/ ctypes.voidptr_t);
 
        SysFile.FindClose = function(handle) {
          if (handle == INVALID_HANDLE) {
            return true;
          } else {
            return handle.dispose(); // Returns the value of |FindClose|.
          }
        };
 
        // Declare libc functions as functions of |OS.Win.File|
 
-       SysFile.CopyFile =
-         declareFFI("CopyFileW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "CopyFile", libc,
+         "CopyFileW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*sourcePath*/ Type.path,
                     /*destPath*/   Type.path,
                     /*bailIfExist*/Type.bool);
 
-       SysFile.CreateDirectory =
-         declareFFI("CreateDirectoryW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "CreateDirectory", libc,
+         "CreateDirectoryW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*name*/   Type.jschar.in_ptr,
                     /*security*/Type.SECURITY_ATTRIBUTES.in_ptr);
 
-       SysFile.CreateFile =
-         declareFFI("CreateFileW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "CreateFile", libc,
+         "CreateFileW", ctypes.winapi_abi,
                     /*return*/  Type.file_HANDLE,
                     /*name*/    Type.path,
                     /*access*/  Type.DWORD,
                     /*share*/   Type.DWORD,
                     /*security*/Type.SECURITY_ATTRIBUTES.in_ptr,
                     /*creation*/Type.DWORD,
                     /*flags*/   Type.DWORD,
                     /*template*/Type.HANDLE);
 
-       SysFile.DeleteFile =
-         declareFFI("DeleteFileW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "DeleteFile", libc,
+         "DeleteFileW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*path*/   Type.path);
 
-       SysFile.FileTimeToSystemTime =
-         declareFFI("FileTimeToSystemTime", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "FileTimeToSystemTime", libc,
+         "FileTimeToSystemTime", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*filetime*/Type.FILETIME.in_ptr,
                     /*systime*/ Type.SystemTime.out_ptr);
 
-       SysFile.FindFirstFile =
-         declareFFI("FindFirstFileW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "FindFirstFile", libc,
+         "FindFirstFileW", ctypes.winapi_abi,
                     /*return*/ Type.find_HANDLE,
                     /*pattern*/Type.path,
                     /*data*/   Type.FindData.out_ptr);
 
-       SysFile.FindNextFile =
-         declareFFI("FindNextFileW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "FindNextFile", libc,
+         "FindNextFileW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*prev*/   Type.find_HANDLE,
                     /*data*/   Type.FindData.out_ptr);
 
-       SysFile.FormatMessage =
-         declareFFI("FormatMessageW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "FormatMessage", libc,
+         "FormatMessageW", ctypes.winapi_abi,
                     /*return*/ Type.DWORD,
                     /*flags*/  Type.DWORD,
                     /*source*/ Type.void_t.in_ptr,
                     /*msgid*/  Type.DWORD,
                     /*langid*/ Type.DWORD,
                     /*buf*/    Type.out_wstring,
                     /*size*/   Type.DWORD,
                     /*Arguments*/Type.void_t.in_ptr
                    );
 
-       SysFile.GetCurrentDirectory =
-         declareFFI("GetCurrentDirectoryW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "GetCurrentDirectory", libc,
+         "GetCurrentDirectoryW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_DWORD,
                     /*length*/ Type.DWORD,
                     /*buf*/    Type.out_path
                    );
 
-       SysFile.GetFileInformationByHandle =
-         declareFFI("GetFileInformationByHandle", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "GetFileInformationByHandle", libc,
+         "GetFileInformationByHandle", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*handle*/ Type.HANDLE,
                     /*info*/   Type.FILE_INFORMATION.out_ptr);
 
-       SysFile.MoveFileEx =
-         declareFFI("MoveFileExW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "MoveFileEx", libc,
+         "MoveFileExW", ctypes.winapi_abi,
                     /*return*/   Type.zero_or_nothing,
                     /*sourcePath*/ Type.path,
                     /*destPath*/ Type.path,
                     /*flags*/    Type.DWORD
                    );
 
-       SysFile.ReadFile =
-         declareFFI("ReadFile", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "ReadFile", libc,
+         "ReadFile", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*file*/   Type.HANDLE,
                     /*buffer*/ Type.voidptr_t,
                     /*nbytes*/ Type.DWORD,
                     /*nbytes_read*/Type.DWORD.out_ptr,
                     /*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
          );
 
-       SysFile.RemoveDirectory =
-         declareFFI("RemoveDirectoryW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "RemoveDirectory", libc,
+         "RemoveDirectoryW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*path*/   Type.path);
 
-       SysFile.SetCurrentDirectory =
-         declareFFI("SetCurrentDirectoryW", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "SetCurrentDirectory", libc,
+         "SetCurrentDirectoryW", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*path*/   Type.path
                    );
 
-       SysFile.SetEndOfFile =
-         declareFFI("SetEndOfFile", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "SetEndOfFile", libc,
+         "SetEndOfFile", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*file*/   Type.HANDLE);
 
-       SysFile.SetFilePointer =
-         declareFFI("SetFilePointer", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "SetFilePointer", libc,
+         "SetFilePointer", ctypes.winapi_abi,
                     /*return*/ Type.negative_or_DWORD,
                     /*file*/   Type.HANDLE,
                     /*distlow*/Type.long,
                     /*disthi*/ Type.long.in_ptr,
                     /*method*/ Type.DWORD);
 
-       SysFile.WriteFile =
-         declareFFI("WriteFile", ctypes.winapi_abi,
+       declareLazyFFI(SysFile, "WriteFile", libc,
+         "WriteFile", ctypes.winapi_abi,
                     /*return*/ Type.zero_or_nothing,
                     /*file*/   Type.HANDLE,
                     /*buffer*/ Type.voidptr_t,
                     /*nbytes*/ Type.DWORD,
                     /*nbytes_wr*/Type.DWORD.out_ptr,
                     /*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
          );
 
-        SysFile.FlushFileBuffers =
-          declareFFI("FlushFileBuffers", ctypes.winapi_abi,
+        declareLazyFFI(SysFile, "FlushFileBuffers", libc,
+          "FlushFileBuffers", ctypes.winapi_abi,
                      /*return*/ Type.zero_or_nothing,
                      /*file*/   Type.HANDLE);
      };
 
      exports.OS.Win = {
        File: {
            _init:  init
        }
--- a/toolkit/components/osfile/tests/xpcshell/test_unique.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_unique.js
@@ -1,31 +1,29 @@
 "use strict";
 
 Components.utils.import("resource://gre/modules/osfile.jsm");
 Components.utils.import("resource://gre/modules/Task.jsm");
 
 function run_test() {
+  do_get_profile();
   run_next_test();
 }
 
 function testFiles(filename) {
   return Task.spawn(function() {
     const MAX_TRIES = 10;
-    let currentDir = yield OS.File.getCurrentDirectory();
-    let path = OS.Path.join(currentDir, filename);
-    let exists = yield OS.File.exists(path);
-    // Check a file with the same name doesn't exist already
-    do_check_false(exists);
+    let profileDir = OS.Constants.Path.profileDir;
+    let path = OS.Path.join(profileDir, filename);
 
     // Ensure that openUnique() uses the file name if there is no file with that name already.
     let openedFile = yield OS.File.openUnique(path);
     do_print("\nCreate new file: " + openedFile.path);
     yield openedFile.file.close();
-    exists = yield OS.File.exists(openedFile.path);
+    let exists = yield OS.File.exists(openedFile.path);
     do_check_true(exists);
     do_check_eq(path, openedFile.path);
     let fileInfo = yield OS.File.stat(openedFile.path);
     do_check_true(fileInfo.size == 0);
 
     // Ensure that openUnique() creates a new file name using a HEX number, as the original name is already taken.
     openedFile = yield OS.File.openUnique(path);
     do_print("\nCreate unique HEX file: " + openedFile.path);