| Index: content/browser/tab_contents/render_view_host_manager.cc | 
| diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc | 
| index 973a1d0e7832c4490cc74e698f2fce67dfc8d133..d06ccf53afe70d572d8491ef56e234636ac5621c 100644 | 
| --- a/content/browser/tab_contents/render_view_host_manager.cc | 
| +++ b/content/browser/tab_contents/render_view_host_manager.cc | 
| @@ -49,6 +49,13 @@ RenderViewHostManager::~RenderViewHostManager() { | 
| RenderViewHost* render_view_host = render_view_host_; | 
| render_view_host_ = NULL; | 
| render_view_host->Shutdown(); | 
| + | 
| +  // Shut down any swapped out RenderViewHosts. | 
| +  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin(); | 
| +       iter != swapped_out_hosts_.end(); | 
| +       ++iter) { | 
| +    iter->second->Shutdown(); | 
| +  } | 
| } | 
|  | 
| void RenderViewHostManager::Init(Profile* profile, | 
| @@ -148,21 +155,17 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { | 
| if (pending_render_view_host_->are_navigations_suspended()) | 
| pending_render_view_host_->SetNavigationsSuspended(false); | 
| } else { | 
| -    // The request has been started and paused, while we're waiting for the | 
| +    // The request has been started and paused while we're waiting for the | 
| // unload handler to finish.  We'll pretend that it did, by notifying the | 
| // IO thread to let the response continue.  The pending renderer will then | 
| // be swapped in as part of the usual DidNavigate logic.  (If the unload | 
| // handler later finishes, this call will be ignored because the state in | 
| // CrossSiteResourceHandler will already be cleaned up.) | 
| -    ViewMsg_ClosePage_Params params; | 
| -    params.closing_process_id = | 
| -        render_view_host_->process()->id(); | 
| -    params.closing_route_id = render_view_host_->routing_id(); | 
| -    params.for_cross_site_transition = true; | 
| +    ViewMsg_SwapOut_Params params; | 
| params.new_render_process_host_id = | 
| pending_render_view_host_->process()->id(); | 
| params.new_request_id = pending_request_id; | 
| -    current_host()->process()->CrossSiteClosePageACK(params); | 
| +    current_host()->process()->CrossSiteSwapOutACK(params); | 
| } | 
| return false; | 
| } | 
| @@ -244,7 +247,7 @@ void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition, | 
|  | 
| if (proceed_to_fire_unload) { | 
| // This is not a cross-site navigation, the tab is being closed. | 
| -      render_view_host_->ClosePage(false, -1, -1); | 
| +      render_view_host_->ClosePage(); | 
| } | 
| } | 
| } | 
| @@ -256,12 +259,12 @@ void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, | 
| return; | 
| DCHECK(pending_render_view_host_); | 
|  | 
| -  // Tell the old renderer to run its onunload handler.  When it finishes, it | 
| -  // will send a ClosePage_ACK to the ResourceDispatcherHost with the given | 
| -  // IDs (of the pending RVH's request), allowing the pending RVH's response to | 
| -  // resume. | 
| -  render_view_host_->ClosePage(true, | 
| -                               new_render_process_host_id, new_request_id); | 
| +  // Tell the old renderer it is being swapped out.  This will fire the unload | 
| +  // handler (without firing the beforeunload handler a second time).  When the | 
| +  // unload handler finishes and the navigation completes, we will send a | 
| +  // message to the ResourceDispatcherHost with the given pending request IDs, | 
| +  // allowing the pending RVH's response to resume. | 
| +  render_view_host_->SwapOut(new_render_process_host_id, new_request_id); | 
|  | 
| // ResourceDispatcherHost has told us to run the onunload handler, which | 
| // means it is not a download or unsafe page, and we are going to perform the | 
| @@ -459,6 +462,17 @@ bool RenderViewHostManager::CreatePendingRenderView( | 
| // we're about to switch away, so that it sends an UpdateState message. | 
| } | 
|  | 
| +  // Check if we've already created an RVH for this SiteInstance. | 
| +  CHECK(instance); | 
| +  RenderViewHostMap::iterator iter = | 
| +      swapped_out_hosts_.find(instance->id()); | 
| +  if (iter != swapped_out_hosts_.end()) { | 
| +    // Re-use the existing RenderViewHost, which has already been initialized. | 
| +    // We'll remove it from the list of swapped out hosts if it commits. | 
| +    pending_render_view_host_ = iter->second; | 
| +    return true; | 
| +  } | 
| + | 
| pending_render_view_host_ = RenderViewHostFactory::Create( | 
| instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_-> | 
| GetControllerForRenderManager().session_storage_namespace()); | 
| @@ -515,9 +529,7 @@ void RenderViewHostManager::CommitPending() { | 
| bool focus_render_view = !will_focus_location_bar && | 
| render_view_host_->view() && render_view_host_->view()->HasFocus(); | 
|  | 
| -  // Hide the current view and prepare to destroy it. | 
| -  // TODO(creis): Get the old RenderViewHost to send us an UpdateState message | 
| -  // before we destroy it. | 
| +  // Hide the current view and prepare to swap it out. | 
| if (render_view_host_->view()) | 
| render_view_host_->view()->Hide(); | 
| RenderViewHost* old_render_view_host = render_view_host_; | 
| @@ -526,6 +538,13 @@ void RenderViewHostManager::CommitPending() { | 
| render_view_host_ = pending_render_view_host_; | 
| pending_render_view_host_ = NULL; | 
|  | 
| +  // If the pending view was on the swapped out list, we can remove it. | 
| +  RenderViewHostMap::iterator iter = swapped_out_hosts_.find( | 
| +      render_view_host_->site_instance()->id()); | 
| +  if (iter != swapped_out_hosts_.end()) { | 
| +    swapped_out_hosts_.erase(iter); | 
| +  } | 
| + | 
| // If the view is gone, then this RenderViewHost died while it was hidden. | 
| // We ignored the RenderViewGone call at the time, so we should send it now | 
| // to make sure the sad tab shows up, etc. | 
| @@ -550,7 +569,9 @@ void RenderViewHostManager::CommitPending() { | 
| Source<NavigationController>(&delegate_->GetControllerForRenderManager()), | 
| Details<RenderViewHostSwitchedDetails>(&details)); | 
|  | 
| -  old_render_view_host->Shutdown(); | 
| +  // Keep track of the old swapped out RVH in case we navigate back to it. | 
| +  swapped_out_hosts_[old_render_view_host->site_instance()->id()] = | 
| +      old_render_view_host; | 
|  | 
| // Let the task manager know that we've swapped RenderViewHosts, since it | 
| // might need to update its process groupings. | 
| @@ -661,7 +682,11 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateForNavigate( | 
| void RenderViewHostManager::CancelPending() { | 
| RenderViewHost* pending_render_view_host = pending_render_view_host_; | 
| pending_render_view_host_ = NULL; | 
| -  pending_render_view_host->Shutdown(); | 
| + | 
| +  // Only shutdown the pending RVH if it isn't currently swapped out. | 
| +  // This can happen if we abort a pending load. | 
| +  if (!IsSwappedOut(pending_render_view_host)) | 
| +    pending_render_view_host->Shutdown(); | 
|  | 
| pending_web_ui_.reset(); | 
| } | 
| @@ -681,9 +706,10 @@ void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { | 
| } | 
|  | 
| void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { | 
| +  // TODO(creis): Abstract out the common code between this and CommitPending. | 
| web_ui_.reset(); | 
|  | 
| -  // Hide the current view and prepare to destroy it. | 
| +  // Hide the current view and prepare to swap it out. | 
| if (render_view_host_->view()) | 
| render_view_host_->view()->Hide(); | 
| RenderViewHost* old_render_view_host = render_view_host_; | 
| @@ -704,6 +730,13 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { | 
| render_view_host_->view()->Show(); | 
| } | 
|  | 
| +  // If the given RVH was on the swapped out list, we can remove it. | 
| +  RenderViewHostMap::iterator iter = swapped_out_hosts_.find( | 
| +      render_view_host_->site_instance()->id()); | 
| +  if (iter != swapped_out_hosts_.end()) { | 
| +    swapped_out_hosts_.erase(iter); | 
| +  } | 
| + | 
| delegate_->UpdateRenderViewSizeForRenderManager(); | 
|  | 
| RenderViewHostSwitchedDetails details; | 
| @@ -714,10 +747,19 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { | 
| Source<NavigationController>(&delegate_->GetControllerForRenderManager()), | 
| Details<RenderViewHostSwitchedDetails>(&details)); | 
|  | 
| -  // This will cause the old RenderViewHost to delete itself. | 
| -  old_render_view_host->Shutdown(); | 
| +  // Keep track of the old swapped out RVH in case we navigate back to it. | 
| +  swapped_out_hosts_[old_render_view_host->site_instance()->id()] = | 
| +      old_render_view_host; | 
|  | 
| // Let the task manager know that we've swapped RenderViewHosts, since it | 
| // might need to update its process groupings. | 
| delegate_->NotifySwappedFromRenderManager(); | 
| } | 
| + | 
| +bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) { | 
| +  if (!rvh->site_instance()) | 
| +    return false; | 
| + | 
| +  return swapped_out_hosts_.find(rvh->site_instance()->id()) != | 
| +      swapped_out_hosts_.end(); | 
| +} | 
|  |