diff --git a/lib/fs.js b/lib/fs.js
index 7b50412ea76fa9..8a028bf79943e7 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -43,6 +43,7 @@ const internalUtil = require('internal/util');
 const assertEncoding = internalFS.assertEncoding;
 const stringToFlags = internalFS.stringToFlags;
 const getPathFromURL = internalURL.getPathFromURL;
+const { StorageObject } = require('internal/querystring');
 
 Object.defineProperty(exports, 'constants', {
   configurable: false,
@@ -1514,10 +1515,23 @@ fs.unwatchFile = function(filename, listener) {
 };
 
 
-// Regex to find the device root, including trailing slash. E.g. 'c:\\'.
-const splitRootRe = isWindows ?
-  /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/ :
-  /^[/]*/;
+var splitRoot;
+if (isWindows) {
+  // Regex to find the device root on Windows (e.g. 'c:\\'), including trailing
+  // slash.
+  const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/;
+  splitRoot = function splitRoot(str) {
+    return splitRootRe.exec(str)[0];
+  };
+} else {
+  splitRoot = function splitRoot(str) {
+    for (var i = 0; i < str.length; ++i) {
+      if (str.charCodeAt(i) !== 47/*'/'*/)
+        return str.slice(0, i);
+    }
+    return str;
+  };
+}
 
 function encodeRealpathResult(result, options) {
   if (!options || !options.encoding || options.encoding === 'utf8')
@@ -1545,11 +1559,17 @@ if (isWindows) {
   nextPart = function nextPart(p, i) { return p.indexOf('/', i); };
 }
 
+const emptyObj = new StorageObject();
 fs.realpathSync = function realpathSync(p, options) {
-  options = getOptions(options, {});
-  handleError((p = getPathFromURL(p)));
-  if (typeof p !== 'string')
-    p += '';
+  if (!options)
+    options = emptyObj;
+  else
+    options = getOptions(options, emptyObj);
+  if (typeof p !== 'string') {
+    handleError((p = getPathFromURL(p)));
+    if (typeof p !== 'string')
+      p += '';
+  }
   nullCheck(p);
   p = pathModule.resolve(p);
 
@@ -1559,8 +1579,8 @@ fs.realpathSync = function realpathSync(p, options) {
     return maybeCachedResult;
   }
 
-  const seenLinks = {};
-  const knownHard = {};
+  const seenLinks = new StorageObject();
+  const knownHard = new StorageObject();
   const original = p;
 
   // current character position in p
@@ -1573,10 +1593,8 @@ fs.realpathSync = function realpathSync(p, options) {
   var previous;
 
   // Skip over roots
-  var m = splitRootRe.exec(p);
-  pos = m[0].length;
-  current = m[0];
-  base = m[0];
+  current = base = splitRoot(p);
+  pos = current.length;
 
   // On windows, check that the root exists. On unix there is no need.
   if (isWindows && !knownHard[base]) {
@@ -1615,7 +1633,8 @@ fs.realpathSync = function realpathSync(p, options) {
       // Use stats array directly to avoid creating an fs.Stats instance just
       // for our internal use.
 
-      binding.lstat(pathModule._makeLong(base));
+      var baseLong = pathModule._makeLong(base);
+      binding.lstat(baseLong);
 
       if ((statValues[1/*mode*/] & S_IFMT) !== S_IFLNK) {
         knownHard[base] = true;
@@ -1631,13 +1650,13 @@ fs.realpathSync = function realpathSync(p, options) {
         var dev = statValues[0/*dev*/].toString(32);
         var ino = statValues[7/*ino*/].toString(32);
         id = `${dev}:${ino}`;
-        if (seenLinks.hasOwnProperty(id)) {
+        if (seenLinks[id]) {
           linkTarget = seenLinks[id];
         }
       }
       if (linkTarget === null) {
-        binding.stat(pathModule._makeLong(base));
-        linkTarget = binding.readlink(pathModule._makeLong(base));
+        binding.stat(baseLong);
+        linkTarget = binding.readlink(baseLong);
       }
       resolvedLink = pathModule.resolve(previous, linkTarget);
 
@@ -1649,10 +1668,8 @@ fs.realpathSync = function realpathSync(p, options) {
     p = pathModule.resolve(resolvedLink, p.slice(pos));
 
     // Skip over roots
-    m = splitRootRe.exec(p);
-    pos = m[0].length;
-    current = m[0];
-    base = m[0];
+    current = base = splitRoot(p);
+    pos = current.length;
 
     // On windows, check that the root exists. On unix there is no need.
     if (isWindows && !knownHard[base]) {
@@ -1668,17 +1685,22 @@ fs.realpathSync = function realpathSync(p, options) {
 
 fs.realpath = function realpath(p, options, callback) {
   callback = maybeCallback(typeof options === 'function' ? options : callback);
-  options = getOptions(options, {});
-  if (handleError((p = getPathFromURL(p)), callback))
-    return;
-  if (typeof p !== 'string')
-    p += '';
+  if (!options)
+    options = emptyObj;
+  else
+    options = getOptions(options, emptyObj);
+  if (typeof p !== 'string') {
+    if (handleError((p = getPathFromURL(p)), callback))
+      return;
+    if (typeof p !== 'string')
+      p += '';
+  }
   if (!nullCheck(p, callback))
     return;
   p = pathModule.resolve(p);
 
-  const seenLinks = {};
-  const knownHard = {};
+  const seenLinks = new StorageObject();
+  const knownHard = new StorageObject();
 
   // current character position in p
   var pos;
@@ -1689,11 +1711,8 @@ fs.realpath = function realpath(p, options, callback) {
   // the partial path scanned in the previous round, with slash
   var previous;
 
-  var m = splitRootRe.exec(p);
-  pos = m[0].length;
-  current = m[0];
-  base = m[0];
-  previous = '';
+  current = base = splitRoot(p);
+  pos = current.length;
 
   // On windows, check that the root exists. On unix there is no need.
   if (isWindows && !knownHard[base]) {
@@ -1756,7 +1775,7 @@ fs.realpath = function realpath(p, options, callback) {
       var dev = statValues[0/*ino*/].toString(32);
       var ino = statValues[7/*ino*/].toString(32);
       id = `${dev}:${ino}`;
-      if (seenLinks.hasOwnProperty(id)) {
+      if (seenLinks[id]) {
         return gotTarget(null, seenLinks[id], base);
       }
     }
@@ -1780,11 +1799,8 @@ fs.realpath = function realpath(p, options, callback) {
   function gotResolvedLink(resolvedLink) {
     // resolve the link, then start over
     p = pathModule.resolve(resolvedLink, p.slice(pos));
-    var m = splitRootRe.exec(p);
-    pos = m[0].length;
-    current = m[0];
-    base = m[0];
-    previous = '';
+    current = base = splitRoot(p);
+    pos = current.length;
 
     // On windows, check that the root exists. On unix there is no need.
     if (isWindows && !knownHard[base]) {