Add logic to convert empty SiteInstances to a default SiteInstance.

This change allows a top-level empty SiteInstance to become the default
SiteInstance if the URL for the top-level frame does not require a
dedicated process. This allows the top-level frame and any subframes
that do not require a dedicated process to share the same default
SiteInstance process.

Bug: 958060,78757
Change-Id: I920860b822474157897a0f3e3534cca87984599c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1693778
Commit-Queue: Aaron Colwell <acolwell@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680472}
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc
index 0726c4f..1e6b4b9 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -101,6 +101,25 @@
       SiteInstanceImpl::DetermineProcessLockURL(isolation_context_, url);
 }
 
+bool BrowsingInstance::TrySettingDefaultSiteInstance(
+    SiteInstanceImpl* site_instance,
+    const GURL& url) {
+  DCHECK(!site_instance->HasSite());
+  const GURL site_url = GetSiteForURL(url);
+  if (default_site_instance_ ||
+      !SiteInstanceImpl::CanBePlacedInDefaultSiteInstance(isolation_context_,
+                                                          url, site_url)) {
+    return false;
+  }
+
+  // Note: |default_site_instance_| must be set before SetSite() call to
+  // properly trigger default SiteInstance behavior inside that method.
+  default_site_instance_ = site_instance;
+  site_instance->SetSite(SiteInstanceImpl::GetDefaultSiteURL());
+  site_url_set_.insert(site_url);
+  return true;
+}
+
 scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURLHelper(
     const GURL& url,
     bool allow_default_instance) {
diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h
index acbf074..906a1ee 100644
--- a/content/browser/browsing_instance.h
+++ b/content/browser/browsing_instance.h
@@ -169,6 +169,14 @@
   // returning the default SiteInstance.
   bool IsSiteInDefaultSiteInstance(const GURL& site_url) const;
 
+  // Attempts to convert |site_instance| into a default SiteInstance,
+  // if |url| can be placed inside a default SiteInstance, and the default
+  // SiteInstance has not already been set for this object.
+  // Returns true if |site_instance| was successfully converted to a default
+  // SiteInstance. Otherwise, returns false.
+  bool TrySettingDefaultSiteInstance(SiteInstanceImpl* site_instance,
+                                     const GURL& url);
+
   // Helper function used by other methods in this class to ensure consistent
   // mapping between |url| and site URL.
   // Note: This should not be used by code outside this class.
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index 5421001..29e7e7d 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "content/browser/frame_host/frame_tree.h"
@@ -1265,12 +1266,16 @@
   WaitForLoadStop(contents);
 
   // Make sure we did a process transfer back to "b.is".
-  EXPECT_EQ(
-      " Site A ------------ proxies for B\n"
-      "   +--Site B ------- proxies for A\n"
-      "Where A = http://a.com/\n"
-      "      B = http://b.is/",
-      FrameTreeVisualizer().DepictFrameTree(root));
+  const std::string kExpectedSiteURL =
+      AreDefaultSiteInstancesEnabled()
+          ? SiteInstanceImpl::GetDefaultSiteURL().spec()
+          : "http://a.com/";
+  EXPECT_EQ(base::StringPrintf(" Site A ------------ proxies for B\n"
+                               "   +--Site B ------- proxies for A\n"
+                               "Where A = %s\n"
+                               "      B = http://b.is/",
+                               kExpectedSiteURL.c_str()),
+            FrameTreeVisualizer().DepictFrameTree(root));
 }
 
 #if !defined(OS_ANDROID)
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index aa060ad..190e5f06 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2485,9 +2485,17 @@
   EXPECT_EQ(1, our_controller.GetEntryCount());
   EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
   EXPECT_FALSE(our_controller.GetPendingEntry());
-  EXPECT_EQ(
-      url,
-      our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Verify we get the default SiteInstance since |url| does not require a
+    // dedicated process.
+    EXPECT_TRUE(our_controller.GetLastCommittedEntry()
+                    ->site_instance()
+                    ->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(
+        url,
+        our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
+  }
   EXPECT_EQ(RestoreType::NONE,
             our_controller.GetEntryAtIndex(0)->restore_type());
 
@@ -2548,9 +2556,17 @@
   EXPECT_EQ(1, our_controller.GetEntryCount());
   EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
   EXPECT_FALSE(our_controller.GetPendingEntry());
-  EXPECT_EQ(
-      url,
-      our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Verify we get the default SiteInstance since |url| does not require a
+    // dedicated process.
+    EXPECT_TRUE(our_controller.GetLastCommittedEntry()
+                    ->site_instance()
+                    ->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(
+        url,
+        our_controller.GetLastCommittedEntry()->site_instance()->GetSiteURL());
+  }
   EXPECT_EQ(RestoreType::NONE,
             our_controller.GetEntryAtIndex(0)->restore_type());
 }
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 91980a8..9edc8538 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1424,7 +1424,7 @@
     if (!instance->HasSite() &&
         SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
             instance->GetIsolationContext(), common_params_.url)) {
-      instance->SetSite(common_params_.url);
+      instance->ConvertToDefaultOrSetSite(common_params_.url);
     }
   }
 
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index d4b98d5..64cf6d0 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -264,7 +264,7 @@
   SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
   if (!site_instance->HasSite() &&
       SiteInstanceImpl::ShouldAssignSiteForURL(params.url)) {
-    site_instance->SetSite(params.url);
+    site_instance->ConvertToDefaultOrSetSite(params.url);
   }
 
   // Need to update MIME type here because it's referred to in
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index 2afced1..5ed6d5d8 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -104,8 +104,12 @@
   // Commit the navigation.
   navigation->Commit();
   EXPECT_TRUE(main_test_rfh()->is_active());
-  EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
-            main_test_rfh()->GetSiteInstance()->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
+              main_test_rfh()->GetSiteInstance()->GetSiteURL());
+  }
   EXPECT_EQ(kUrl, contents()->GetLastCommittedURL());
 
   // The main RenderFrameHost should not have been changed, and the renderer
@@ -157,8 +161,12 @@
   // Commit the navigation.
   navigation->Commit();
   EXPECT_TRUE(main_test_rfh()->is_active());
-  EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl2),
-            main_test_rfh()->GetSiteInstance()->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl2),
+              main_test_rfh()->GetSiteInstance()->GetSiteURL());
+  }
   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
 }
@@ -960,10 +968,20 @@
   const GURL kUrl1("http://wikipedia.org/");
   const GURL kUrl2("data:text/html,test");
 
+  // Isolate kUrl1 so it can't be mapped into a default SiteInstance along with
+  // kUrl2. This ensures that the speculative RenderFrameHost will always be
+  // used because the URLs map to different SiteInstances.
+  ChildProcessSecurityPolicy::GetInstance()->AddIsolatedOrigins(
+      {url::Origin::Create(kUrl1)},
+      ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
+      browser_context());
+
   // Navigate to an initial site.
   contents()->NavigateAndCommit(kUrl1);
   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
 
+  EXPECT_FALSE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
+
   // Navigate to a data url. The request should have been sent to the IO
   // thread and not committed immediately.
   auto navigation =
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 8ca7df4..37593f39 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1501,7 +1501,7 @@
     // scheme) can be reused for subsequent navigations in the same WebContents.
     // See http://crbug.com/386542.
     if (dest_is_restore && SiteInstanceImpl::ShouldAssignSiteForURL(dest_url))
-      current_instance_impl->SetSite(dest_url);
+      current_instance_impl->ConvertToDefaultOrSetSite(dest_url);
 
     return SiteInstanceDescriptor(current_instance_impl);
   }
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index b70f831..2ff8be00 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -278,7 +278,11 @@
       new_shell, embedded_test_server()->GetURL("foo.com", "/title1.html")));
   scoped_refptr<SiteInstance> new_site_instance(
       new_shell->web_contents()->GetSiteInstance());
-  EXPECT_NE(orig_site_instance, new_site_instance);
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_EQ(orig_site_instance, new_site_instance);
+  } else {
+    EXPECT_NE(orig_site_instance, new_site_instance);
+  }
 
   // We should no longer have script access to the opened window's location.
   success = false;
@@ -289,6 +293,7 @@
   EXPECT_FALSE(success);
 
   // We now navigate the window to an about:blank page.
+  TestNavigationObserver navigation_observer(new_shell->web_contents());
   success = false;
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
       shell(), "window.domAutomationController.send(clickBlankTargetedLink());",
@@ -296,7 +301,8 @@
   EXPECT_TRUE(success);
 
   // Wait for the navigation in the new window to finish.
-  WaitForLoadStop(new_shell->web_contents());
+  navigation_observer.Wait();
+
   GURL blank_url(url::kAboutBlankURL);
   EXPECT_EQ(blank_url,
             new_shell->web_contents()->GetLastCommittedURL());
@@ -753,6 +759,13 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
   StartEmbeddedServer();
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed to get a non-default
+    // SiteInstance for navigations to this origin.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
+
   // Load a page with links that open in a new window.
   NavigateToPageWithLinks(shell());
 
@@ -846,6 +859,12 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        PreserveTopFrameWindowNameOnCrossProcessNavigations) {
   StartEmbeddedServer();
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed it is placed in a different
+    // process.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
 
   GURL main_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -870,7 +889,7 @@
   EXPECT_TRUE(NavigateToURLInSameBrowsingInstance(new_shell, foo_url));
   scoped_refptr<SiteInstance> new_site_instance(
       new_shell->web_contents()->GetSiteInstance());
-  EXPECT_NE(orig_site_instance, new_site_instance);
+  EXPECT_NE(orig_site_instance->GetProcess(), new_site_instance->GetProcess());
 
   // window.name should still be "foo".
   name = "";
@@ -908,6 +927,12 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        SupportCrossProcessPostMessage) {
   StartEmbeddedServer();
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed it is placed in a different
+    // process.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
 
   // Load a page with links that open in a new window.
   NavigateToPageWithLinks(shell());
@@ -1046,6 +1071,12 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        SupportCrossProcessPostMessageWithMessagePort) {
   StartEmbeddedServer();
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed it is placed in a different
+    // process.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
 
   // Load a page with links that open in a new window.
   NavigateToPageWithLinks(shell());
@@ -1131,6 +1162,13 @@
                        AllowTargetedNavigationsInOpenerAfterSwap) {
   StartEmbeddedServer();
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed to get a non-default
+    // SiteInstance for navigations to this origin.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
+
   // Load a page with links that open in a new window.
   NavigateToPageWithLinks(shell());
 
@@ -1231,6 +1269,12 @@
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        ProcessExitWithSwappedOutViews) {
   StartEmbeddedServer();
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed to get a non-default
+    // SiteInstance for navigations to this origin.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
 
   // Load a page with links that open in a new window.
   NavigateToPageWithLinks(shell());
@@ -1932,6 +1976,8 @@
   if (AreAllSitesIsolatedForTesting()) {
     EXPECT_EQ(kRedirectSiteURL,
               speculative_rfh->GetSiteInstance()->GetSiteURL());
+  } else if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
   } else {
     EXPECT_EQ(kOriginalSiteURL,
               speculative_rfh->GetSiteInstance()->GetSiteURL());
@@ -1973,7 +2019,12 @@
                         ->render_manager()
                         ->speculative_frame_host();
   CHECK(speculative_rfh);
-  EXPECT_EQ(kOriginalSiteURL, speculative_rfh->GetSiteInstance()->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(kOriginalSiteURL,
+              speculative_rfh->GetSiteInstance()->GetSiteURL());
+  }
   if (AreAllSitesIsolatedForTesting())
     EXPECT_NE(site_instance_id, speculative_rfh->GetSiteInstance()->GetId());
 }
@@ -2203,6 +2254,13 @@
                        DontPreemptNavigationWithFrameTreeUpdate) {
   StartEmbeddedServer();
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed to get a non-default
+    // SiteInstance for navigations to this origin.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
+
   // 1. Load a page that deletes its iframe during unload.
   NavigateToURL(shell(),
                 embedded_test_server()->GetURL("/remove_frame_on_unload.html"));
@@ -2841,6 +2899,13 @@
                        ReinitializeOpenerChainAfterCrashAndReload) {
   StartEmbeddedServer();
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed to get a non-default
+    // SiteInstance for navigations to this origin.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
+
   GURL main_url = embedded_test_server()->GetURL("/title1.html");
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
@@ -2904,6 +2969,12 @@
 // the other popup, and ensure that the opener is updated in all processes.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, UpdateOpener) {
   StartEmbeddedServer();
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed it is placed in a different
+    // process.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
 
   GURL main_url = embedded_test_server()->GetURL("/post_message.html");
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -2928,10 +2999,10 @@
   Shell* bar_shell = OpenPopup(shell(), bar_url, "bar");
   EXPECT_TRUE(bar_shell);
 
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            foo_shell->web_contents()->GetSiteInstance());
-  EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
-            bar_shell->web_contents()->GetSiteInstance());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance()->GetProcess(),
+            foo_shell->web_contents()->GetSiteInstance()->GetProcess());
+  EXPECT_EQ(shell()->web_contents()->GetSiteInstance()->GetProcess(),
+            bar_shell->web_contents()->GetSiteInstance()->GetProcess());
 
   // Initially, both popups' openers should point to main window.
   FrameTreeNode* foo_root =
@@ -3705,14 +3776,17 @@
         "      B = http://b.com/",
         FrameTreeVisualizer().DepictFrameTree(root));
   } else {
-    EXPECT_EQ(
-        " Site A\n"
-        "   +--Site A\n"
-        "        +--Site A\n"
-        "             +--Site A\n"
-        "                  +--Site A\n"
-        "Where A = http://a.com/",
-        FrameTreeVisualizer().DepictFrameTree(root));
+    const GURL kExpectedSiteURL = AreDefaultSiteInstancesEnabled()
+                                      ? SiteInstanceImpl::GetDefaultSiteURL()
+                                      : GURL("http://a.com/");
+    EXPECT_EQ(std::string(" Site A\n"
+                          "   +--Site A\n"
+                          "        +--Site A\n"
+                          "             +--Site A\n"
+                          "                  +--Site A\n"
+                          "Where A = ") +
+                  kExpectedSiteURL.spec(),
+              FrameTreeVisualizer().DepictFrameTree(root));
   }
   FrameTreeNode* bottom_child =
       root->child_at(0)->child_at(0)->child_at(0)->child_at(0);
@@ -3760,12 +3834,15 @@
 
   // The FrameTree contains two successful instances of the url plus an
   // unsuccessfully-navigated third instance with a blank URL.
-  EXPECT_EQ(
-      " Site A\n"
-      "   +--Site A\n"
-      "        +--Site A\n"
-      "Where A = http://a.com/",
-      FrameTreeVisualizer().DepictFrameTree(root));
+  const GURL kExpectedSiteURL = AreDefaultSiteInstancesEnabled()
+                                    ? SiteInstanceImpl::GetDefaultSiteURL()
+                                    : GURL("http://a.com/");
+  EXPECT_EQ(std::string(" Site A\n"
+                        "   +--Site A\n"
+                        "        +--Site A\n"
+                        "Where A = ") +
+                kExpectedSiteURL.spec(),
+            FrameTreeVisualizer().DepictFrameTree(root));
 
   // The URL of the grandchild has not changed.
   EXPECT_EQ(expected_url, grandchild->current_url());
@@ -3791,12 +3868,15 @@
 
   // The third navigation should fail and be cancelled, leaving a FrameTree with
   // a height of 2.
-  EXPECT_EQ(
-      " Site A\n"
-      "   +--Site A\n"
-      "        +--Site A\n"
-      "Where A = http://a.com/",
-      FrameTreeVisualizer().DepictFrameTree(root));
+  const GURL kExpectedSiteURL = AreDefaultSiteInstancesEnabled()
+                                    ? SiteInstanceImpl::GetDefaultSiteURL()
+                                    : GURL("http://a.com/");
+  EXPECT_EQ(std::string(" Site A\n"
+                        "   +--Site A\n"
+                        "        +--Site A\n"
+                        "Where A = ") +
+                kExpectedSiteURL.spec(),
+            FrameTreeVisualizer().DepictFrameTree(root));
 
   EXPECT_EQ(GURL(url::kAboutBlankURL),
             root->child_at(0)->child_at(0)->current_url());
@@ -5799,7 +5879,11 @@
   GURL url2(embedded_test_server()->GetURL("foo.com", "/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url2));
   EXPECT_EQ(instance1, web_contents->GetMainFrame()->GetSiteInstance());
-  EXPECT_EQ(GURL("http://foo.com"), instance1->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(instance1->IsDefaultSiteInstance());
+  } else {
+    EXPECT_EQ(GURL("http://foo.com"), instance1->GetSiteURL());
+  }
 
   // Navigate to bar.com, which destroys the previous RenderProcessHost.
   GURL url3(embedded_test_server()->GetURL("bar.com", "/title1.html"));
@@ -5807,7 +5891,19 @@
       process1, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   EXPECT_TRUE(NavigateToURL(shell(), url3));
   exit_observer.Wait();
-  EXPECT_NE(instance1, web_contents->GetMainFrame()->GetSiteInstance());
+
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Verify that the new navigation also results in a default SiteInstance,
+    // and verify that it is not related to |instance1| because the navigation
+    // swapped to a new BrowsingInstance.
+    EXPECT_TRUE(web_contents->GetMainFrame()
+                    ->GetSiteInstance()
+                    ->IsDefaultSiteInstance());
+    EXPECT_FALSE(instance1->IsRelatedSiteInstance(
+        web_contents->GetMainFrame()->GetSiteInstance()));
+  } else {
+    EXPECT_NE(instance1, web_contents->GetMainFrame()->GetSiteInstance());
+  }
 
   // At this point, process1 is deleted, and the first entry is unfortunately
   // pointing to instance1, which has been locked to url2 and has no process.
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 144548a..1fdf536 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
@@ -332,6 +333,19 @@
   void SetUp() override {
     RenderViewHostImplTestHarness::SetUp();
     WebUIControllerFactory::RegisterFactory(&factory_);
+
+    if (AreDefaultSiteInstancesEnabled()) {
+      // Isolate |isolated_cross_site_url()| so we can't get a default
+      // SiteInstance for it.
+      ChildProcessSecurityPolicyImpl::GetInstance()->AddIsolatedOrigins(
+          {url::Origin::Create(isolated_cross_site_url())},
+          ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
+          browser_context());
+
+      // Reset the WebContents so the isolated origin will be honored by
+      // all BrowsingInstances used in the test.
+      SetContents(CreateTestWebContents());
+    }
   }
 
   void TearDown() override {
@@ -345,6 +359,10 @@
 
   void set_webui_type(int type) { factory_.set_webui_type(type); }
 
+  GURL isolated_cross_site_url() const {
+    return GURL("http://isolated-cross-site.com");
+  }
+
   // Creates a test RenderViewHost that's swapped out.
   void CreateSwappedOutRenderViewHost() {
     const GURL kChromeURL(GetWebUIURL("foo"));
@@ -694,12 +712,18 @@
   TestRenderFrameHost* rfh2 = main_test_rfh();
   SiteInstanceImpl* instance2 = rfh2->GetSiteInstance();
 
-  // rvh2 is on chromium.org which is different from google.com on
-  // which other tabs are.
-  EXPECT_EQ(instance2->active_frame_count(), 1U);
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(instance1->IsDefaultSiteInstance());
+    EXPECT_EQ(instance1->active_frame_count(), 3U);
+    EXPECT_EQ(instance1, instance2);
+  } else {
+    // rvh2 is on chromium.org which is different from google.com on
+    // which other tabs are.
+    EXPECT_EQ(instance2->active_frame_count(), 1U);
 
-  // There are two active views on google.com now.
-  EXPECT_EQ(instance1->active_frame_count(), 2U);
+    // There are two active views on google.com now.
+    EXPECT_EQ(instance1->active_frame_count(), 2U);
+  }
 
   // Navigate to the original origin (google.com).
   contents()->NavigateAndCommit(kUrl1);
@@ -1145,7 +1169,7 @@
 // See http://crbug.com/93427.
 TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to two pages.
   contents()->NavigateAndCommit(kUrl1);
@@ -1183,7 +1207,7 @@
 // JavaScript calls (http://crbug.com/99202).
 TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRFHs) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
   const GURL kChromeUrl(GetWebUIURL("foo"));
 
   // Navigate to an initial URL.
@@ -1193,6 +1217,8 @@
   scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
   RenderFrameDeletedObserver rfh1_deleted_observer(rfh1);
   TestRenderViewHost* rvh1 = test_rvh();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create 2 new tabs and simulate them being the opener chain for the main
   // tab.  They should be in the same SiteInstance.
@@ -1257,12 +1283,14 @@
 // Test that a page can disown the opener of the WebContents.
 TEST_F(RenderFrameHostManagerTest, DisownOpener) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   TestRenderFrameHost* rfh1 = main_test_rfh();
   scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create a new tab and simulate having it be the opener for the main tab.
   std::unique_ptr<TestWebContents> opener1(
@@ -1308,12 +1336,14 @@
 // in progress.
 TEST_F(RenderFrameHostManagerTest, DisownOpenerDuringNavigation) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   scoped_refptr<SiteInstanceImpl> site_instance1 =
       main_test_rfh()->GetSiteInstance();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create a new tab and simulate having it be the opener for the main tab.
   std::unique_ptr<TestWebContents> opener1(
@@ -1351,12 +1381,14 @@
 // commits.
 TEST_F(RenderFrameHostManagerTest, DisownOpenerAfterNavigation) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   scoped_refptr<SiteInstanceImpl> site_instance1 =
       main_test_rfh()->GetSiteInstance();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create a new tab and simulate having it be the opener for the main tab.
   std::unique_ptr<TestWebContents> opener1(
@@ -1387,7 +1419,7 @@
 // those associated RenderViews crashes. http://crbug.com/258993
 TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
@@ -1635,7 +1667,7 @@
 
 TEST_F(RenderFrameHostManagerTest, CloseWithPendingWhileUnresponsive) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   CloseWebContentsDelegate close_delegate;
   contents()->SetDelegate(&close_delegate);
@@ -1794,7 +1826,7 @@
 TEST_F(RenderFrameHostManagerTest,
        CancelPendingProperlyDeletesOrSwaps) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
   RenderFrameHostImpl* pending_rfh = nullptr;
   base::TimeTicks now = base::TimeTicks::Now();
 
@@ -2103,12 +2135,14 @@
 // chain.
 TEST_F(RenderFrameHostManagerTest, CreateOpenerProxiesWithCycleOnOpenerChain) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   TestRenderFrameHost* rfh1 = main_test_rfh();
   scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create 2 new tabs and construct the opener chain as follows:
   //
@@ -2166,12 +2200,14 @@
 // to itself.
 TEST_F(RenderFrameHostManagerTest, CreateOpenerProxiesWhenOpenerPointsToSelf) {
   const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl2 = isolated_cross_site_url();
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   TestRenderFrameHost* rfh1 = main_test_rfh();
   scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            site_instance1->IsDefaultSiteInstance());
 
   // Create an opener tab, and simulate that its opener points to itself.
   std::unique_ptr<TestWebContents> opener(
@@ -3237,8 +3273,13 @@
   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kFooUrl);
   scoped_refptr<SiteInstanceImpl> initial_instance =
       main_test_rfh()->GetSiteInstance();
-  EXPECT_EQ(kFooUrl, initial_instance->original_url());
-  EXPECT_EQ(kFooUrl, initial_instance->GetSiteURL());
+  if (AreDefaultSiteInstancesEnabled()) {
+    EXPECT_TRUE(initial_instance->IsDefaultSiteInstance());
+  } else {
+    EXPECT_FALSE(initial_instance->IsDefaultSiteInstance());
+    EXPECT_EQ(kFooUrl, initial_instance->original_url());
+    EXPECT_EQ(kFooUrl, initial_instance->GetSiteURL());
+  }
 
   // Simulate a browser-initiated navigation to an app URL, which should swap
   // processes and create a new SiteInstance in a new BrowsingInstance.
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index ee7f44d..fd15a8b 100644
--- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -129,10 +129,22 @@
       static_cast<WebContentsImpl*>(shell2->web_contents());
   WebContentsImpl* web_contents_http =
       static_cast<WebContentsImpl*>(shell()->web_contents());
-  EXPECT_EQ("http://127.0.0.1/",
-            web_contents_http->GetSiteInstance()->GetSiteURL().spec());
-  EXPECT_EQ("https://127.0.0.1/",
-            web_contents_https->GetSiteInstance()->GetSiteURL().spec());
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Note: Both use the default SiteInstance because the URLs don't require
+    // a dedicated process, but these default SiteInstances are not the same
+    // object because they come from different BrowsingInstances.
+    EXPECT_TRUE(web_contents_http->GetSiteInstance()->IsDefaultSiteInstance());
+    EXPECT_TRUE(web_contents_https->GetSiteInstance()->IsDefaultSiteInstance());
+    EXPECT_NE(web_contents_http->GetSiteInstance(),
+              web_contents_https->GetSiteInstance());
+    EXPECT_FALSE(web_contents_http->GetSiteInstance()->IsRelatedSiteInstance(
+        web_contents_https->GetSiteInstance()));
+  } else {
+    EXPECT_EQ("http://127.0.0.1/",
+              web_contents_http->GetSiteInstance()->GetSiteURL().spec());
+    EXPECT_EQ("https://127.0.0.1/",
+              web_contents_https->GetSiteInstance()->GetSiteURL().spec());
+  }
 
   EXPECT_NE(web_contents_http->GetSiteInstance()->GetProcess(),
             web_contents_https->GetSiteInstance()->GetProcess());
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index 7b662fb..6181257 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -606,10 +606,25 @@
     manager.WaitForNavigationFinished();
   }
 
-  // At this point, the popup and the opener should still be in separate
-  // SiteInstances.
-  EXPECT_NE(new_shell->web_contents()->GetMainFrame()->GetSiteInstance(),
-            root->current_frame_host()->GetSiteInstance());
+  const SiteInstanceImpl* const root_site_instance_impl =
+      static_cast<SiteInstanceImpl*>(
+          root->current_frame_host()->GetSiteInstance());
+  const SiteInstanceImpl* const newshell_site_instance_impl =
+      static_cast<SiteInstanceImpl*>(
+          new_shell->web_contents()->GetMainFrame()->GetSiteInstance());
+  if (AreDefaultSiteInstancesEnabled()) {
+    // When default SiteInstances are enabled, all sites that do not
+    // require a dedicated process all end up in the same default SiteInstance.
+    EXPECT_EQ(newshell_site_instance_impl, root_site_instance_impl);
+    EXPECT_TRUE(newshell_site_instance_impl->IsDefaultSiteInstance());
+  } else {
+    // At this point, the popup and the opener should still be in separate
+    // SiteInstances.
+    EXPECT_NE(newshell_site_instance_impl, root_site_instance_impl);
+    EXPECT_NE(AreAllSitesIsolatedForTesting(),
+              newshell_site_instance_impl->IsDefaultSiteInstance());
+    EXPECT_FALSE(root_site_instance_impl->IsDefaultSiteInstance());
+  }
 
   // Simulate the isolated origin in the popup navigating to www.foo.com.
   {
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index 8d265a1..b0987f5 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -39,6 +39,7 @@
 #include "media/base/media_switches.h"
 #include "media/base/test_data_util.h"
 #include "media/mojo/buildflags.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -76,6 +77,11 @@
         switches::autoplay::kNoUserGestureRequiredPolicy);
   }
 
+  void SetUpOnMainThread() override {
+    // Support multiple sites on the test server.
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
+
  protected:
   void set_process_exit_callback(const base::Closure& callback) {
     process_exit_callback_ = callback;
@@ -953,6 +959,13 @@
       base::BindRepeating(HandleBeacon));
   ASSERT_TRUE(embedded_test_server()->Start());
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "foo.com" so we are guaranteed that navigations to this site
+    // will be in a different process.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"foo.com"});
+  }
+
   NavigateToURL(shell(), embedded_test_server()->GetURL("/send-beacon.html"));
 
   RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
@@ -965,8 +978,10 @@
   rph->AddObserver(this);
   rfh->SetKeepAliveTimeoutForTesting(base::TimeDelta::FromSeconds(30));
 
+  // Navigate to a site that will be in a different process.
   base::TimeTicks start = base::TimeTicks::Now();
-  NavigateToURL(shell(), GURL("data:text/html,<p>hello</p>"));
+  NavigateToURL(shell(),
+                embedded_test_server()->GetURL("foo.com", "/title1.html"));
 
   WaitUntilProcessExits(1);
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 0b9c5b7d..13b94abf 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -14,7 +14,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
-#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/frame_host/navigator.h"
@@ -95,9 +94,16 @@
 // into |target_routing_id| and the pending RenderFrameHost which is used for
 // the attempt is the return value.
 RenderFrameHostImpl* PrepareToDuplicateHosts(Shell* shell,
+                                             net::EmbeddedTestServer* server,
                                              int* target_routing_id) {
   GURL foo("http://foo.com/simple_page.html");
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "bar.com" so we are guaranteed to get a different process
+    // for navigations to this origin.
+    IsolateOriginsForTesting(server, shell->web_contents(), {"bar.com"});
+  }
+
   // Start off with initial navigation, so we get the first process allocated.
   NavigateToURL(shell, foo);
   EXPECT_EQ(base::ASCIIToUTF16("OK"), shell->web_contents()->GetTitle());
@@ -116,7 +122,7 @@
             shell->web_contents()->GetRenderViewHost()->GetRoutingID());
 
   // Now, simulate a link click coming from the renderer.
-  GURL extension_url("https://bar.com/simple_page.html");
+  GURL extension_url("http://bar.com/simple_page.html");
   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents());
   wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
       wc->GetFrameTree()->root()->current_frame_host(), extension_url,
@@ -413,8 +419,8 @@
 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
                        AttemptDuplicateRenderViewHost) {
   int32_t duplicate_routing_id = MSG_ROUTING_NONE;
-  RenderFrameHostImpl* pending_rfh =
-      PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
+  RenderFrameHostImpl* pending_rfh = PrepareToDuplicateHosts(
+      shell(), embedded_test_server(), &duplicate_routing_id);
   EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
 
   mojom::CreateNewWindowParamsPtr params = mojom::CreateNewWindowParams::New();
@@ -432,8 +438,8 @@
 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
                        DISABLED_AttemptDuplicateRenderWidgetHost) {
   int duplicate_routing_id = MSG_ROUTING_NONE;
-  RenderFrameHostImpl* pending_rfh =
-      PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
+  RenderFrameHostImpl* pending_rfh = PrepareToDuplicateHosts(
+      shell(), embedded_test_server(), &duplicate_routing_id);
   EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
 
   mojom::WidgetPtr widget;
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index b29e2479..abcb777c 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -344,6 +344,17 @@
   }
 }
 
+void SiteInstanceImpl::ConvertToDefaultOrSetSite(const GURL& url) {
+  DCHECK(!has_site_);
+
+  if (ShouldAllowDefaultSiteInstance() &&
+      browsing_instance_->TrySettingDefaultSiteInstance(this, url)) {
+    return;
+  }
+
+  SetSite(url);
+}
+
 const GURL& SiteInstanceImpl::GetSiteURL() {
   return site_;
 }
@@ -494,6 +505,11 @@
 
 bool SiteInstanceImpl::IsSameSiteWithURL(const GURL& url) {
   if (IsDefaultSiteInstance()) {
+    // about:blank URLs should always be considered same site just like they are
+    // in IsSameWebSite().
+    if (url.IsAboutBlank())
+      return true;
+
     // Consider |url| the same site if it could be handled by the
     // default SiteInstance and we don't already have a SiteInstance for
     // this URL.
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 17b08b2..1edb9fd6 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -186,8 +186,17 @@
   // Set the web site that this SiteInstance is rendering pages for.
   // This includes the scheme and registered domain, but not the port.  If the
   // URL does not have a valid registered domain, then the full hostname is
-  // stored.
+  // stored. This method does not convert this instance into a default
+  // SiteInstance, but the BrowsingInstance will call this method with |url|
+  // set to GetDefaultSiteURL(), when it is creating its default SiteInstance.
   void SetSite(const GURL& url);
+
+  // Similar to SetSite(), but first attempts to convert this object to a
+  // default SiteInstance if |url| can be placed inside a default SiteInstance.
+  // If conversion is not possible, then the normal SetSite() logic is run.
+  void ConvertToDefaultOrSetSite(const GURL& url);
+
+  // Returns whether SetSite() has been called.
   bool HasSite() const;
 
   // Returns whether there is currently a related SiteInstance (registered with
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 6b5be14..eca62cc 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -3773,6 +3773,14 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url(embedded_test_server()->GetURL("/hello.html"));
 
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Isolate "b.com" so we are guaranteed to get a different process
+    // for navigations to this origin. Doing this ensures that a
+    // speculative RenderFrameHost is used.
+    IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
+                             {"b.com"});
+  }
+
   WebContents* attached_web_contents = shell()->web_contents();
 
   WebContents::CreateParams create_params(
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index c51f779..7d3ca62 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "components/download/public/common/download_url_parameters.h"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/navigator.h"
@@ -261,6 +262,19 @@
     RenderViewHostImplTestHarness::SetUp();
     WebUIControllerFactory::RegisterFactory(
         ContentWebUIControllerFactory::GetInstance());
+
+    if (AreDefaultSiteInstancesEnabled()) {
+      // Isolate |isolated_cross_site_url()| so we can't get a default
+      // SiteInstance for it.
+      ChildProcessSecurityPolicyImpl::GetInstance()->AddIsolatedOrigins(
+          {url::Origin::Create(isolated_cross_site_url())},
+          ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
+          browser_context());
+
+      // Reset the WebContents so the isolated origin will be honored by
+      // all BrowsingInstances used in the test.
+      SetContents(CreateTestWebContents());
+    }
   }
 
   void TearDown() override {
@@ -274,6 +288,10 @@
         ->media_web_contents_observer()
         ->has_audio_wake_lock_for_testing();
   }
+
+  GURL isolated_cross_site_url() const {
+    return GURL("http://isolated-cross-site.com");
+  }
 };
 
 class TestWebContentsObserver : public WebContentsObserver {
@@ -650,7 +668,7 @@
   EXPECT_EQ(instance1, contents2->GetSiteInstance());
 
   // Navigate first contents to a new site.
-  const GURL url2a("http://www.yahoo.com");
+  const GURL url2a = isolated_cross_site_url();
   auto navigation1 =
       NavigationSimulator::CreateBrowserInitiated(url2a, contents());
   navigation1->SetTransition(ui::PAGE_TRANSITION_LINK);
@@ -661,7 +679,7 @@
   EXPECT_NE(instance1, instance2a);
 
   // Navigate second contents to the same site as the first tab.
-  const GURL url2b("http://www.yahoo.com/foo");
+  const GURL url2b = isolated_cross_site_url().Resolve("/foo");
   auto navigation2 =
       NavigationSimulator::CreateBrowserInitiated(url2b, contents2.get());
   navigation2->SetTransition(ui::PAGE_TRANSITION_LINK);
@@ -724,12 +742,18 @@
   SiteInstanceImpl* orig_site_instance = orig_rfh->GetSiteInstance();
 
   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
-  EXPECT_TRUE(
-      contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Verify that the empty SiteInstance gets converted into a default
+    // SiteInstance because |url| does not require a dedicated process.
+    EXPECT_TRUE(contents()->GetSiteInstance()->IsDefaultSiteInstance());
+  } else {
+    EXPECT_TRUE(
+        contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
+  }
   EXPECT_EQ(url, contents()->GetLastCommittedURL());
 
   // Navigate to another new site (should create a new site instance).
-  const GURL url2("http://www.yahoo.com");
+  const GURL url2 = isolated_cross_site_url();
   auto navigation2 =
       NavigationSimulator::CreateBrowserInitiated(url2, contents());
   navigation2->ReadyToCommit();
@@ -838,11 +862,25 @@
                               regular_url, ui::PAGE_TRANSITION_RELOAD);
   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
   EXPECT_TRUE(orig_instance->HasSite());
+  EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
+            orig_instance->IsDefaultSiteInstance());
 
   // Navigate to another site and verify that a new SiteInstance was created.
   const GURL url("http://www.google.com");
   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
-  EXPECT_NE(orig_instance, contents()->GetSiteInstance());
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Verify this remains the default SiteInstance since |url| does
+    // not require a dedicated process.
+    EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
+
+    // Navigate to a URL that does require a dedicated process and verify that
+    // the SiteInstance changes.
+    NavigationSimulator::NavigateAndCommitFromBrowser(
+        contents(), isolated_cross_site_url());
+    EXPECT_NE(orig_instance, contents()->GetSiteInstance());
+  } else {
+    EXPECT_NE(orig_instance, contents()->GetSiteInstance());
+  }
 
   // Cleanup.
   DeleteContents();
@@ -899,10 +937,19 @@
   }
 
   TestRenderFrameHost* orig_rfh = main_test_rfh();
-  SiteInstance* instance1 = contents()->GetSiteInstance();
+  SiteInstanceImpl* instance1 = contents()->GetSiteInstance();
+
+  const GURL url("http://www.google.com");
+
+  if (AreDefaultSiteInstancesEnabled()) {
+    // Explicitly set the site for this instance so that it cannot be
+    // converted into a default SiteInstance. This ensures that the navigation
+    // to |url2|, which does not require a dedicated process, will not be
+    // mapped to this instance.
+    instance1->SetSite(url);
+  }
 
   // Navigate to URL.
-  const GURL url("http://www.google.com");
   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
 
   // Open a related contents to a second site.