diff --git a/BUILD.gn b/BUILD.gn
index 5f9f3a9..044f7c6 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -205,6 +205,7 @@
   } else {
     deps += [
       "//ios/net:ios_net_unittests",
+      "//ios/public/provider/web",
       "//ios/testing:ocmock_support_unittest",
       "//ios/web:ios_web_unittests",
     ]
diff --git a/DEPS b/DEPS
index 6c08c19..8d273a6 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c94cd7cc01b655b7f4289537962c36a4ee8dd63e',
+  'skia_revision': '1d5127327111e00d0e4530adae73b11ad2ee3f42',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '00820330372dd1588a7f96649ad83fe5ffb9bbbf',
+  'v8_revision': 'fd63469ff634889fcb372187901fd0176f02f1ad',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 70ebeaa..9b1aa0c 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -5,6 +5,18 @@
 source_set("trace_event") {
   sources = [
     "common/trace_event_common.h",
+    "heap_profiler_allocation_context.cc",
+    "heap_profiler_allocation_context.h",
+    "heap_profiler_allocation_context_tracker.cc",
+    "heap_profiler_allocation_context_tracker.h",
+    "heap_profiler_allocation_register.cc",
+    "heap_profiler_allocation_register.h",
+    "heap_profiler_allocation_register_posix.cc",
+    "heap_profiler_allocation_register_win.cc",
+    "heap_profiler_heap_dump_writer.cc",
+    "heap_profiler_heap_dump_writer.h",
+    "heap_profiler_stack_frame_deduplicator.cc",
+    "heap_profiler_stack_frame_deduplicator.h",
     "java_heap_dump_provider_android.cc",
     "java_heap_dump_provider_android.h",
     "memory_allocator_dump.cc",
@@ -18,14 +30,6 @@
     "memory_dump_request_args.h",
     "memory_dump_session_state.cc",
     "memory_dump_session_state.h",
-    "memory_profiler_allocation_context.cc",
-    "memory_profiler_allocation_context.h",
-    "memory_profiler_allocation_register.cc",
-    "memory_profiler_allocation_register.h",
-    "memory_profiler_allocation_register_posix.cc",
-    "memory_profiler_allocation_register_win.cc",
-    "memory_profiler_heap_dump_writer.cc",
-    "memory_profiler_heap_dump_writer.h",
     "process_memory_dump.cc",
     "process_memory_dump.h",
     "process_memory_maps.cc",
@@ -108,11 +112,12 @@
 source_set("trace_event_unittests") {
   testonly = true
   sources = [
+    "heap_profiler_allocation_context_tracker_unittest.cc",
+    "heap_profiler_allocation_register_unittest.cc",
+    "heap_profiler_stack_frame_deduplicator_unittest.cc",
     "java_heap_dump_provider_android_unittest.cc",
     "memory_allocator_dump_unittest.cc",
     "memory_dump_manager_unittest.cc",
-    "memory_profiler_allocation_context_unittest.cc",
-    "memory_profiler_allocation_register_unittest.cc",
     "process_memory_dump_unittest.cc",
     "process_memory_totals_dump_provider_unittest.cc",
     "trace_config_memory_test_util.h",
diff --git a/base/trace_event/heap_profiler_allocation_context.cc b/base/trace_event/heap_profiler_allocation_context.cc
new file mode 100644
index 0000000..657f00c
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.cc
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#include <cstring>
+
+#include "base/hash.h"
+
+namespace base {
+namespace trace_event {
+
+bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
+  // Pointer equality of the stack frames is assumed, so instead of doing a deep
+  // string comparison on all of the frames, a |memcmp| suffices.
+  return std::memcmp(lhs.frames, rhs.frames, sizeof(lhs.frames)) == 0;
+}
+
+bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
+  return (lhs.backtrace == rhs.backtrace) && (lhs.type_id == rhs.type_id);
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+using base::trace_event::AllocationContext;
+using base::trace_event::Backtrace;
+
+size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
+  return base::SuperFastHash(reinterpret_cast<const char*>(backtrace.frames),
+                             sizeof(backtrace.frames));
+}
+
+size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
+  size_t ctx_hash = hash<Backtrace>()(ctx.backtrace);
+
+  // Multiply one side to break the commutativity of +. Multiplication with a
+  // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
+  // randomness is preserved. The type ID is assumed to be distributed randomly
+  // already so there is no need to hash it.
+  return (ctx_hash * 3) + static_cast<size_t>(ctx.type_id);
+}
+
+}  // BASE_HASH_NAMESPACE
diff --git a/base/trace_event/heap_profiler_allocation_context.h b/base/trace_event/heap_profiler_allocation_context.h
new file mode 100644
index 0000000..070daf1
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.h
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// When heap profiling is enabled, tracing keeps track of the allocation
+// context for each allocation intercepted. It is generated by the
+// |AllocationContextTracker| which keeps stacks of context in TLS.
+// The tracker is initialized lazily.
+
+// The backtrace in the allocation context is a snapshot of the stack. For now,
+// this is the pseudo stack where frames are created by trace event macros. In
+// the future, we might add the option to use the native call stack. In that
+// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
+// have different implementations that can be selected by a compile time flag.
+
+// The number of stack frames stored in the backtrace is a trade off between
+// memory used for tracing and accuracy. Measurements done on a prototype
+// revealed that:
+//
+// - In 60 percent of the cases, stack depth <= 7.
+// - In 87 percent of the cases, stack depth <= 9.
+// - In 95 percent of the cases, stack depth <= 11.
+//
+// See the design doc (https://goo.gl/4s7v7b) for more details.
+
+using StackFrame = const char*;
+
+struct BASE_EXPORT Backtrace {
+  // Unused backtrace frames are filled with nullptr frames. If the stack is
+  // higher than what can be stored here, the bottom frames are stored. Based
+  // on the data above, a depth of 12 captures the full stack in the vast
+  // majority of the cases.
+  StackFrame frames[12];
+};
+
+bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
+
+// The |AllocationContext| is context metadata that is kept for every allocation
+// when heap profiling is enabled. To simplify memory management for book-
+// keeping, this struct has a fixed size. All |const char*|s here must have
+// static lifetime.
+// TODO(ruuda): Make the default constructor private to avoid accidentally
+// constructing an instance and forgetting to initialize it. Only
+// |AllocationContextTracker| should be able to construct. (And tests.)
+struct BASE_EXPORT AllocationContext {
+  // A type ID is a number that is unique for every C++ type. A type ID is
+  // stored instead of the type name to avoid inflating the binary with type
+  // name strings. There is an out of band lookup table mapping IDs to the type
+  // names. A value of 0 means that the type is not known.
+  using TypeId = uint16_t;
+
+  Backtrace backtrace;
+  TypeId type_id;
+};
+
+bool BASE_EXPORT operator==(const AllocationContext& lhs,
+                            const AllocationContext& rhs);
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct hash<base::trace_event::Backtrace> {
+  size_t operator()(const base::trace_event::Backtrace& backtrace) const;
+};
+
+template <>
+struct hash<base::trace_event::AllocationContext> {
+  size_t operator()(const base::trace_event::AllocationContext& context) const;
+};
+
+}  // BASE_HASH_NAMESPACE
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
new file mode 100644
index 0000000..b58fb60
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -0,0 +1,121 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+#include <algorithm>
+
+#include "base/atomicops.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
+
+namespace {
+
+ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
+
+// This function is added to the TLS slot to clean up the instance when the
+// thread exits.
+void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
+  delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
+}
+
+// Returns a pointer past the end of the fixed-size array |array| of |T| of
+// length |N|, identical to C++11 |std::end|.
+template <typename T, int N>
+T* End(T(&array)[N]) {
+  return array + N;
+}
+
+}  // namespace
+
+AllocationContextTracker::AllocationContextTracker() {}
+AllocationContextTracker::~AllocationContextTracker() {}
+
+// static
+AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
+  auto tracker =
+      static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
+
+  if (!tracker) {
+    tracker = new AllocationContextTracker();
+    g_tls_alloc_ctx_tracker.Set(tracker);
+  }
+
+  return tracker;
+}
+
+// static
+void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
+  // When enabling capturing, also initialize the TLS slot. This does not create
+  // a TLS instance yet.
+  if (enabled && !g_tls_alloc_ctx_tracker.initialized())
+    g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
+
+  // Release ordering ensures that when a thread observes |capture_enabled_| to
+  // be true through an acquire load, the TLS slot has been initialized.
+  subtle::Release_Store(&capture_enabled_, enabled);
+}
+
+// static
+void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
+  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+  // Impose a limit on the height to verify that every push is popped, because
+  // in practice the pseudo stack never grows higher than ~20 frames.
+  DCHECK_LT(tracker->pseudo_stack_.size(), 128u);
+  tracker->pseudo_stack_.push_back(frame);
+}
+
+// static
+void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
+  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+  // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+  // scope, the frame was never pushed, so it is possible that pop is called
+  // on an empty stack.
+  if (tracker->pseudo_stack_.empty())
+    return;
+
+  // Assert that pushes and pops are nested correctly. This DCHECK can be
+  // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
+  // without a corresponding TRACE_EVENT_BEGIN).
+  DCHECK_EQ(frame, tracker->pseudo_stack_.back())
+      << "Encountered an unmatched TRACE_EVENT_END";
+
+  tracker->pseudo_stack_.pop_back();
+}
+
+// static
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+  AllocationContextTracker* tracker = GetThreadLocalTracker();
+  AllocationContext ctx;
+
+  // Fill the backtrace.
+  {
+    auto src = tracker->pseudo_stack_.begin();
+    auto dst = ctx.backtrace.frames;
+    auto src_end = tracker->pseudo_stack_.end();
+    auto dst_end = End(ctx.backtrace.frames);
+
+    // Copy as much of the bottom of the pseudo stack into the backtrace as
+    // possible.
+    for (; src != src_end && dst != dst_end; src++, dst++)
+      *dst = *src;
+
+    // If there is room for more, fill the remaining slots with empty frames.
+    std::fill(dst, dst_end, nullptr);
+  }
+
+  ctx.type_id = 0;
+
+  return ctx;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
new file mode 100644
index 0000000..9c9a313
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+// The allocation context tracker keeps track of thread-local context for heap
+// profiling. It includes a pseudo stack of trace events. On every allocation
+// the tracker provides a snapshot of its context in the form of an
+// |AllocationContext| that is to be stored together with the allocation
+// details.
+class BASE_EXPORT AllocationContextTracker {
+ public:
+  // Globally enables capturing allocation context.
+  // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
+  // Or at least have something that guards agains enable -> disable -> enable?
+  static void SetCaptureEnabled(bool enabled);
+
+  // Returns whether capturing allocation context is enabled globally.
+  inline static bool capture_enabled() {
+    // A little lag after heap profiling is enabled or disabled is fine, it is
+    // more important that the check is as cheap as possible when capturing is
+    // not enabled, so do not issue a memory barrier in the fast path.
+    if (subtle::NoBarrier_Load(&capture_enabled_) == 0)
+      return false;
+
+    // In the slow path, an acquire load is required to pair with the release
+    // store in |SetCaptureEnabled|. This is to ensure that the TLS slot for
+    // the thread-local allocation context tracker has been initialized if
+    // |capture_enabled| returns true.
+    return subtle::Acquire_Load(&capture_enabled_) != 0;
+  }
+
+  // Pushes a frame onto the thread-local pseudo stack.
+  static void PushPseudoStackFrame(StackFrame frame);
+
+  // Pops a frame from the thread-local pseudo stack.
+  static void PopPseudoStackFrame(StackFrame frame);
+
+  // Returns a snapshot of the current thread-local context.
+  static AllocationContext GetContextSnapshot();
+
+  ~AllocationContextTracker();
+
+ private:
+  AllocationContextTracker();
+
+  static AllocationContextTracker* GetThreadLocalTracker();
+
+  static subtle::Atomic32 capture_enabled_;
+
+  // The pseudo stack where frames are |TRACE_EVENT| names.
+  std::vector<StackFrame> pseudo_stack_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/base/trace_event/memory_profiler_allocation_context_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
similarity index 63%
rename from base/trace_event/memory_profiler_allocation_context_unittest.cc
rename to base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
index ffc27b688..fe3f407 100644
--- a/base/trace_event/memory_profiler_allocation_context_unittest.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/trace_event.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,12 +19,6 @@
 const char kFroyo[] = "Froyo";
 const char kGingerbread[] = "Gingerbread";
 
-const char kBrowserMain[] = "BrowserMain";
-const char kRendererMain[] = "RendererMain";
-const char kCreateWidget[] = "CreateWidget";
-const char kInitialize[] = "Initialize";
-const char kMalloc[] = "malloc";
-
 // Returns a pointer past the end of the fixed-size array |array| of |T| of
 // length |N|, identical to C++11 |std::end|.
 template <typename T, int N>
@@ -60,7 +55,7 @@
     ASSERT_EQ(nullptr, frame);
 }
 
-class AllocationContextTest : public testing::Test {
+class AllocationContextTrackerTest : public testing::Test {
  public:
   void SetUp() override {
     TraceConfig config("");
@@ -74,12 +69,10 @@
   }
 };
 
-class StackFrameDeduplicatorTest : public testing::Test {};
-
 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
 // Also check that |GetContextSnapshot| fills the backtrace with null pointers
 // when the pseudo stack height is less than the capacity.
-TEST_F(AllocationContextTest, PseudoStackScopedTrace) {
+TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
   StackFrame c = kCupcake;
   StackFrame d = kDonut;
   StackFrame e = kEclair;
@@ -122,7 +115,7 @@
 
 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
 // |TRACE_EVENT_END| macros.
-TEST_F(AllocationContextTest, PseudoStackBeginEndTrace) {
+TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
   StackFrame c = kCupcake;
   StackFrame d = kDonut;
   StackFrame e = kEclair;
@@ -160,7 +153,7 @@
   AssertBacktraceEmpty();
 }
 
-TEST_F(AllocationContextTest, PseudoStackMixedTrace) {
+TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
   StackFrame c = kCupcake;
   StackFrame d = kDonut;
   StackFrame e = kEclair;
@@ -198,7 +191,7 @@
   AssertBacktraceEmpty();
 }
 
-TEST_F(AllocationContextTest, BacktraceTakesTop) {
+TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
   // Push 12 events onto the pseudo stack.
   TRACE_EVENT0("Testing", kCupcake);
   TRACE_EVENT0("Testing", kCupcake);
@@ -231,102 +224,5 @@
   }
 }
 
-TEST_F(StackFrameDeduplicatorTest, SingleBacktrace) {
-  Backtrace bt = {
-      {kBrowserMain, kCreateWidget, kMalloc, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-
-  // The call tree should look like this (index in brackets).
-  //
-  // BrowserMain [0]
-  // + CreateWidget [1]
-  //   + malloc [2]
-
-  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
-  ASSERT_EQ(2, dedup->Insert(bt));
-
-  auto iter = dedup->begin();
-  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
-  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
-  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
-  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
-  ASSERT_EQ(kMalloc, (iter + 2)->frame);
-  ASSERT_EQ(1, (iter + 2)->parent_frame_index);
-
-  ASSERT_EQ(iter + 3, dedup->end());
-}
-
-// Test that there can be different call trees (there can be multiple bottom
-// frames). Also verify that frames with the same name but a different caller
-// are represented as distinct nodes.
-TEST_F(StackFrameDeduplicatorTest, MultipleRoots) {
-  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-  Backtrace bt1 = {{kRendererMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-
-  // The call tree should look like this (index in brackets).
-  //
-  // BrowserMain [0]
-  // + CreateWidget [1]
-  // RendererMain [2]
-  // + CreateWidget [3]
-  //
-  // Note that there will be two instances of Donut, with different parents.
-
-  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
-  ASSERT_EQ(1, dedup->Insert(bt0));
-  ASSERT_EQ(3, dedup->Insert(bt1));
-
-  auto iter = dedup->begin();
-  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
-  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
-  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
-  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
-  ASSERT_EQ(kRendererMain, (iter + 2)->frame);
-  ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
-
-  ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
-  ASSERT_EQ(2, (iter + 3)->parent_frame_index);
-
-  ASSERT_EQ(iter + 4, dedup->end());
-}
-
-TEST_F(StackFrameDeduplicatorTest, Deduplication) {
-  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-  Backtrace bt1 = {{kBrowserMain, kInitialize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-
-  // The call tree should look like this (index in brackets).
-  //
-  // BrowserMain [0]
-  // + CreateWidget [1]
-  // + Initialize [2]
-  //
-  // Note that Cupcake will be re-used.
-
-  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
-  ASSERT_EQ(1, dedup->Insert(bt0));
-  ASSERT_EQ(2, dedup->Insert(bt1));
-
-  auto iter = dedup->begin();
-  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
-  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
-
-  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
-  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
-
-  ASSERT_EQ(kInitialize, (iter + 2)->frame);
-  ASSERT_EQ(0, (iter + 2)->parent_frame_index);
-
-  ASSERT_EQ(iter + 3, dedup->end());
-
-  // Inserting the same backtrace again should return the index of the existing
-  // node.
-  ASSERT_EQ(1, dedup->Insert(bt0));
-  ASSERT_EQ(2, dedup->Insert(bt1));
-  ASSERT_EQ(dedup->begin() + 3, dedup->end());
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_profiler_allocation_register.cc b/base/trace_event/heap_profiler_allocation_register.cc
similarity index 97%
rename from base/trace_event/memory_profiler_allocation_register.cc
rename to base/trace_event/heap_profiler_allocation_register.cc
index 4421c0a..37647ee 100644
--- a/base/trace_event/memory_profiler_allocation_register.cc
+++ b/base/trace_event/heap_profiler_allocation_register.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/memory_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
 
 #include "base/trace_event/trace_event_memory_overhead.h"
 
@@ -113,7 +113,7 @@
   // The list head is in |buckets_| at the hash offset.
   CellIndex* idx_ptr = &buckets_[Hash(address)];
 
-  // Chase down the list until the cell that holds |key| is found,
+  // Chase down the list until the cell that holds |address| is found,
   // or until the list ends.
   while (*idx_ptr != 0 && cells_[*idx_ptr].allocation.address != address)
     idx_ptr = &cells_[*idx_ptr].next;
diff --git a/base/trace_event/memory_profiler_allocation_register.h b/base/trace_event/heap_profiler_allocation_register.h
similarity index 93%
rename from base/trace_event/memory_profiler_allocation_register.h
rename to base/trace_event/heap_profiler_allocation_register.h
index 8eb4a9d5..7c4ba99 100644
--- a/base/trace_event/memory_profiler_allocation_register.h
+++ b/base/trace_event/heap_profiler_allocation_register.h
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_REGISTER_H_
-#define BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_REGISTER_H_
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
 
 #include <stdint.h>
 
 #include "base/logging.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
 
 namespace base {
 namespace trace_event {
@@ -116,9 +117,9 @@
   // Returns a value in the range [0, kNumBuckets - 1] (inclusive).
   static uint32_t Hash(void* address);
 
-  // Allocates a region of virtual address space of |min_size| rounded up to the
-  // system page size. The memory is zeroed by the system. A guard page is added
-  // after the end.
+  // Allocates a region of virtual address space of |size| rounded up to the
+  // system page size. The memory is zeroed by the system. A guard page is
+  // added after the end.
   static void* AllocateVirtualMemory(size_t size);
 
   // Frees a region of virtual address space allocated by a call to
@@ -142,7 +143,7 @@
   Cell* const cells_;
 
   // The array of indices into |cells_|. |buckets_[Hash(address)]| will contain
-  // the index of the head of the linked list for |Hash(key)|. A value of 0
+  // the index of the head of the linked list for |Hash(address)|. A value of 0
   // indicates an empty list. This array is backed by mmapped memory.
   CellIndex* const buckets_;
 
@@ -161,4 +162,4 @@
 }  // namespace trace_event
 }  // namespace base
 
-#endif  // BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_REGISTER_H_
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
diff --git a/base/trace_event/memory_profiler_allocation_register_posix.cc b/base/trace_event/heap_profiler_allocation_register_posix.cc
similarity index 95%
rename from base/trace_event/memory_profiler_allocation_register_posix.cc
rename to base/trace_event/heap_profiler_allocation_register_posix.cc
index e2231a8..bc175e4 100644
--- a/base/trace_event/memory_profiler_allocation_register_posix.cc
+++ b/base/trace_event/heap_profiler_allocation_register_posix.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/memory_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
 
 #include <sys/mman.h>
 #include <unistd.h>
diff --git a/base/trace_event/memory_profiler_allocation_register_unittest.cc b/base/trace_event/heap_profiler_allocation_register_unittest.cc
similarity index 98%
rename from base/trace_event/memory_profiler_allocation_register_unittest.cc
rename to base/trace_event/heap_profiler_allocation_register_unittest.cc
index bb5aeb3..f17ffbcf 100644
--- a/base/trace_event/memory_profiler_allocation_register_unittest.cc
+++ b/base/trace_event/heap_profiler_allocation_register_unittest.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/memory_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
 
 #include "base/process/process_metrics.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
diff --git a/base/trace_event/memory_profiler_allocation_register_win.cc b/base/trace_event/heap_profiler_allocation_register_win.cc
similarity index 96%
rename from base/trace_event/memory_profiler_allocation_register_win.cc
rename to base/trace_event/heap_profiler_allocation_register_win.cc
index b94c75e..5bcac63 100644
--- a/base/trace_event/memory_profiler_allocation_register_win.cc
+++ b/base/trace_event/heap_profiler_allocation_register_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/memory_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
 
 #include <windows.h>
 
diff --git a/base/trace_event/memory_profiler_heap_dump_writer.cc b/base/trace_event/heap_profiler_heap_dump_writer.cc
similarity index 88%
rename from base/trace_event/memory_profiler_heap_dump_writer.cc
rename to base/trace_event/heap_profiler_heap_dump_writer.cc
index 60e9929..16316505 100644
--- a/base/trace_event/memory_profiler_heap_dump_writer.cc
+++ b/base/trace_event/heap_profiler_heap_dump_writer.cc
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/memory_profiler_heap_dump_writer.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
 
 #include <algorithm>
 #include <iterator>
+#include <utility>
+#include <vector>
 
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
 #include "base/trace_event/trace_event_argument.h"
 
 namespace base {
@@ -25,8 +27,10 @@
   return lhs.second > rhs.second;
 }
 
+// Converts a |hash_map<T, size_t>| into a vector of (T, size_t) pairs that is
+// ordered from high |size_t| to low |size_t|.
 template <typename T>
-std::vector<std::pair<T, size_t>> SortDescending(
+std::vector<std::pair<T, size_t>> SortBySizeDescending(
     const hash_map<T, size_t>& grouped) {
   std::vector<std::pair<T, size_t>> sorted;
   std::copy(grouped.begin(), grouped.end(), std::back_inserter(sorted));
@@ -60,9 +64,8 @@
     bytes_by_type[context_size.first.type_id] += context_size.second;
   }
 
-  // Sort the backtraces and type IDs by size.
-  auto sorted_bytes_by_backtrace = SortDescending(bytes_by_backtrace);
-  auto sorted_bytes_by_type = SortDescending(bytes_by_type);
+  auto sorted_bytes_by_backtrace = SortBySizeDescending(bytes_by_backtrace);
+  auto sorted_bytes_by_type = SortBySizeDescending(bytes_by_type);
 
   traced_value_->BeginArray("entries");
 
diff --git a/base/trace_event/memory_profiler_heap_dump_writer.h b/base/trace_event/heap_profiler_heap_dump_writer.h
similarity index 89%
rename from base/trace_event/memory_profiler_heap_dump_writer.h
rename to base/trace_event/heap_profiler_heap_dump_writer.h
index 10a64e5..4b995433 100644
--- a/base/trace_event/memory_profiler_heap_dump_writer.h
+++ b/base/trace_event/heap_profiler_heap_dump_writer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_TRACE_EVENT_MEMORY_PROFILER_HEAP_DUMP_WRITER_H_
-#define BASE_TRACE_EVENT_MEMORY_PROFILER_HEAP_DUMP_WRITER_H_
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
 
 #include <string>
 
@@ -11,13 +11,13 @@
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
 
 namespace base {
 namespace trace_event {
 
-class AllocationRegister;
 class TracedValue;
+class StackFrameDeduplicator;
 
 // Helper class to dump a snapshot of an |AllocationRegister| or other heap
 // bookkeeping structure into a |TracedValue|. This class is intended to be
@@ -72,4 +72,4 @@
 }  // namespace trace_event
 }  // namespace base
 
-#endif  // BASE_TRACE_EVENT_MEMORY_PROFILER_HEAP_DUMP_WRITER_H_
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
new file mode 100644
index 0000000..09c4a3e
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -0,0 +1,112 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+
+#include <string>
+#include <utility>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
+                                             int parent_frame_index)
+    : frame(frame), parent_frame_index(parent_frame_index) {}
+StackFrameDeduplicator::FrameNode::~FrameNode() {}
+
+StackFrameDeduplicator::StackFrameDeduplicator() {}
+StackFrameDeduplicator::~StackFrameDeduplicator() {}
+
+int StackFrameDeduplicator::Insert(const Backtrace& bt) {
+  int frame_index = -1;
+  std::map<StackFrame, int>* nodes = &roots_;
+
+  for (size_t i = 0; i < arraysize(bt.frames); i++) {
+    if (!bt.frames[i])
+      break;
+
+    auto node = nodes->find(bt.frames[i]);
+    if (node == nodes->end()) {
+      // There is no tree node for this frame yet, create it. The parent node
+      // is the node associated with the previous frame.
+      FrameNode frame_node(bt.frames[i], frame_index);
+
+      // The new frame node will be appended, so its index is the current size
+      // of the vector.
+      frame_index = static_cast<int>(frames_.size());
+
+      // Add the node to the trie so it will be found next time.
+      nodes->insert(std::make_pair(bt.frames[i], frame_index));
+
+      // Append the node after modifying |nodes|, because the |frames_| vector
+      // might need to resize, and this invalidates the |nodes| pointer.
+      frames_.push_back(frame_node);
+    } else {
+      // A tree node for this frame exists. Look for the next one.
+      frame_index = node->second;
+    }
+
+    nodes = &frames_[frame_index].children;
+  }
+
+  return frame_index;
+}
+
+void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+  out->append("{");  // Begin the |stackFrames| dictionary.
+
+  int i = 0;
+  auto frame_node = begin();
+  auto it_end = end();
+  std::string stringify_buffer;
+
+  while (frame_node != it_end) {
+    // The |stackFrames| format is a dictionary, not an array, so the
+    // keys are stringified indices. Write the index manually, then use
+    // |TracedValue| to format the object. This is to avoid building the
+    // entire dictionary as a |TracedValue| in memory.
+    SStringPrintf(&stringify_buffer, "\"%d\":", i);
+    out->append(stringify_buffer);
+
+    scoped_refptr<TracedValue> frame_node_value = new TracedValue;
+    frame_node_value->SetString("name", frame_node->frame);
+    if (frame_node->parent_frame_index >= 0) {
+      SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
+      frame_node_value->SetString("parent", stringify_buffer);
+    }
+    frame_node_value->AppendAsTraceFormat(out);
+
+    i++;
+    frame_node++;
+
+    if (frame_node != it_end)
+      out->append(",");
+  }
+
+  out->append("}");  // End the |stackFrames| dictionary.
+}
+
+void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  // The sizes here are only estimates; they fail to take into account the
+  // overhead of the tree nodes for the map, but as an estimate this should be
+  // fine.
+  size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+  size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+  size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+  for (const FrameNode& node : frames_)
+    maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
+  overhead->Add("StackFrameDeduplicator",
+                sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+                sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
new file mode 100644
index 0000000..a7b00ca
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// A data structure that allows grouping a set of backtraces in a space-
+// efficient manner by creating a call tree and writing it as a set of (node,
+// parent) pairs. The tree nodes reference both parent and children. The parent
+// is referenced by index into |frames_|. The children are referenced via a map
+// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
+// lookup of a backtrace for deduplication, and a tree for compact storage in
+// the trace log.
+class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
+ public:
+  // A node in the call tree.
+  struct FrameNode {
+    FrameNode(StackFrame frame, int parent_frame_index);
+    ~FrameNode();
+
+    StackFrame frame;
+
+    // The index of the parent stack frame in |frames_|, or -1 if there is no
+    // parent frame (when it is at the bottom of the call stack).
+    int parent_frame_index;
+
+    // Indices into |frames_| of frames called from the current frame.
+    std::map<StackFrame, int> children;
+  };
+
+  using ConstIterator = std::vector<FrameNode>::const_iterator;
+
+  StackFrameDeduplicator();
+
+  // Inserts a backtrace and returns the index of its leaf node in |frames_|.
+  // Returns -1 if the backtrace is empty.
+  int Insert(const Backtrace& bt);
+
+  // Iterators over the frame nodes in the call tree.
+  ConstIterator begin() const { return frames_.begin(); }
+  ConstIterator end() const { return frames_.end(); }
+
+  // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
+  // the trace log.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+  ~StackFrameDeduplicator() override;
+
+  std::map<StackFrame, int> roots_;
+  std::vector<FrameNode> frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
new file mode 100644
index 0000000..b87c7b1
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+const char kMalloc[] = "malloc";
+
+class StackFrameDeduplicatorTest : public testing::Test {};
+
+TEST_F(StackFrameDeduplicatorTest, SingleBacktrace) {
+  Backtrace bt = {
+      {kBrowserMain, kCreateWidget, kMalloc, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //     malloc [2]
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(2, dedup->Insert(bt));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kMalloc, (iter + 2)->frame);
+  ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+}
+
+// Test that there can be different call trees (there can be multiple bottom
+// frames). Also verify that frames with the same name but a different caller
+// are represented as distinct nodes.
+TEST_F(StackFrameDeduplicatorTest, MultipleRoots) {
+  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  Backtrace bt1 = {{kRendererMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  // RendererMain [2]
+  //   CreateWidget [3]
+  //
+  // Note that there will be two instances of CreateWidget,
+  // with different parents.
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(3, dedup->Insert(bt1));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kRendererMain, (iter + 2)->frame);
+  ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
+  ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+
+  ASSERT_EQ(iter + 4, dedup->end());
+}
+
+TEST_F(StackFrameDeduplicatorTest, Deduplication) {
+  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  Backtrace bt1 = {{kBrowserMain, kInitialize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //   Initialize [2]
+  //
+  // Note that BrowserMain will be re-used.
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(2, dedup->Insert(bt1));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kInitialize, (iter + 2)->frame);
+  ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+
+  // Inserting the same backtrace again should return the index of the existing
+  // node.
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(2, dedup->Insert(bt1));
+  ASSERT_EQ(dedup->begin() + 3, dedup->end());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 19bdcc4..354d782 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -12,10 +12,11 @@
 #include "base/compiler_specific.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
 #include "base/trace_event/malloc_dump_provider.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/memory_dump_session_state.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "build/build_config.h"
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index 84d07334..8a032079 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -5,17 +5,13 @@
 #ifndef BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
 #define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
 
-#include <string>
-
 #include "base/base_export.h"
 #include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
 
 namespace base {
 namespace trace_event {
 
-class StackFrameDeduplicator;
-
 // Container for state variables that should be shared across all the memory
 // dumps in a tracing session.
 class BASE_EXPORT MemoryDumpSessionState
diff --git a/base/trace_event/memory_profiler_allocation_context.cc b/base/trace_event/memory_profiler_allocation_context.cc
deleted file mode 100644
index ed8d759..0000000
--- a/base/trace_event/memory_profiler_allocation_context.cc
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/trace_event/memory_profiler_allocation_context.h"
-
-#include <algorithm>
-#include <cstring>
-
-#include "base/hash.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_local_storage.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "base/trace_event/trace_event_memory_overhead.h"
-
-namespace base {
-namespace trace_event {
-
-subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
-
-namespace {
-
-ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
-
-// This function is added to the TLS slot to clean up the instance when the
-// thread exits.
-void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
-  delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
-}
-
-}  // namespace
-
-AllocationStack::AllocationStack() {}
-AllocationStack::~AllocationStack() {}
-
-bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
-  // Pointer equality of the stack frames is assumed, so instead of doing a deep
-  // string comparison on all of the frames, a |memcmp| suffices.
-  return std::memcmp(lhs.frames, rhs.frames, sizeof(lhs.frames)) == 0;
-}
-
-StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
-                                             int parent_frame_index)
-    : frame(frame), parent_frame_index(parent_frame_index) {}
-StackFrameDeduplicator::FrameNode::~FrameNode() {}
-
-StackFrameDeduplicator::StackFrameDeduplicator() {}
-StackFrameDeduplicator::~StackFrameDeduplicator() {}
-
-int StackFrameDeduplicator::Insert(const Backtrace& bt) {
-  int frame_index = -1;
-  std::map<StackFrame, int>* nodes = &roots_;
-
-  for (size_t i = 0; i < arraysize(bt.frames); i++) {
-    if (!bt.frames[i])
-      break;
-
-    auto node = nodes->find(bt.frames[i]);
-    if (node == nodes->end()) {
-      // There is no tree node for this frame yet, create it. The parent node
-      // is the node associated with the previous frame.
-      FrameNode frame_node(bt.frames[i], frame_index);
-
-      // The new frame node will be appended, so its index is the current size
-      // of the vector.
-      frame_index = static_cast<int>(frames_.size());
-
-      // Add the node to the trie so it will be found next time.
-      nodes->insert(std::make_pair(bt.frames[i], frame_index));
-
-      // Append the node after modifying |children|, because the vector might
-      // need to resize, and this invalidates the |children| pointer.
-      frames_.push_back(frame_node);
-    } else {
-      // A tree node for this frame exists. Look for the next one.
-      frame_index = node->second;
-    }
-
-    nodes = &frames_[frame_index].children;
-  }
-
-  return frame_index;
-}
-
-void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
-  out->append("{");  // Begin the |stackFrames| dictionary.
-
-  int i = 0;
-  auto frame_node = begin();
-  auto it_end = end();
-  std::string stringify_buffer;
-  while (frame_node != it_end) {
-    // The |stackFrames| format is a dictionary, not an array, so the
-    // keys are stringified indices. Write the index manually, then use
-    // |TracedValue| to format the object. This is to avoid building the
-    // entire dictionary as a |TracedValue| in memory.
-    SStringPrintf(&stringify_buffer, "\"%d\":", i);
-    out->append(stringify_buffer);
-
-    scoped_refptr<TracedValue> frame_node_value = new TracedValue;
-    frame_node_value->SetString("name", frame_node->frame);
-    if (frame_node->parent_frame_index >= 0) {
-      SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
-      frame_node_value->SetString("parent", stringify_buffer);
-    }
-    frame_node_value->AppendAsTraceFormat(out);
-
-    i++;
-    frame_node++;
-
-    if (frame_node != it_end)
-      out->append(",");
-  }
-
-  out->append("}");  // End the |stackFrames| dictionary.
-}
-
-void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
-    TraceEventMemoryOverhead* overhead) {
-
-  // The sizes here are only estimates; they fail to take into account the
-  // overhead of the tree nodes for the map, but as an estimate this should be
-  // fine.
-  size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
-  size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
-  size_t frames_resident = frames_.size() * sizeof(FrameNode);
-
-  for (const FrameNode& node : frames_)
-    maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
-
-  overhead->Add("StackFrameDeduplicator",
-                sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
-                sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
-}
-
-bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
-  return (lhs.backtrace == rhs.backtrace) && (lhs.type_id == rhs.type_id);
-}
-
-AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
-  auto tracker =
-      static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
-
-  if (!tracker) {
-    tracker = new AllocationContextTracker();
-    g_tls_alloc_ctx_tracker.Set(tracker);
-  }
-
-  return tracker;
-}
-
-AllocationContextTracker::AllocationContextTracker() {}
-AllocationContextTracker::~AllocationContextTracker() {}
-
-// static
-void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
-  // When enabling capturing, also initialize the TLS slot. This does not create
-  // a TLS instance yet.
-  if (enabled && !g_tls_alloc_ctx_tracker.initialized())
-    g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
-
-  // Release ordering ensures that when a thread observes |capture_enabled_| to
-  // be true through an acquire load, the TLS slot has been initialized.
-  subtle::Release_Store(&capture_enabled_, enabled);
-}
-
-// static
-void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
-  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
-  tracker->pseudo_stack_.push(frame);
-}
-
-// static
-void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
-  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
-  tracker->pseudo_stack_.pop(frame);
-}
-
-// Returns a pointer past the end of the fixed-size array |array| of |T| of
-// length |N|, identical to C++11 |std::end|.
-template <typename T, int N>
-T* End(T(&array)[N]) {
-  return array + N;
-}
-
-// static
-AllocationContext AllocationContextTracker::GetContextSnapshot() {
-  AllocationContextTracker* tracker = GetThreadLocalTracker();
-  AllocationContext ctx;
-
-  // Fill the backtrace.
-  {
-    auto src = tracker->pseudo_stack_.bottom();
-    auto dst = ctx.backtrace.frames;
-    auto src_end = tracker->pseudo_stack_.top();
-    auto dst_end = End(ctx.backtrace.frames);
-
-    // Copy as much of the bottom of the pseudo stack into the backtrace as
-    // possible.
-    for (; src != src_end && dst != dst_end; src++, dst++)
-      *dst = *src;
-
-    // If there is room for more, fill the remaining slots with empty frames.
-    std::fill(dst, dst_end, nullptr);
-  }
-
-  ctx.type_id = 0;
-
-  return ctx;
-}
-
-}  // namespace trace_event
-}  // namespace base
-
-namespace BASE_HASH_NAMESPACE {
-using base::trace_event::AllocationContext;
-using base::trace_event::Backtrace;
-
-size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
-  return base::SuperFastHash(reinterpret_cast<const char*>(backtrace.frames),
-                             sizeof(backtrace.frames));
-}
-
-size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
-  size_t ctx_hash = hash<Backtrace>()(ctx.backtrace);
-
-  // Multiply one side to break the commutativity of +. Multiplication with a
-  // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
-  // randomness is preserved. The type ID is assumed to be distributed randomly
-  // already so there is no need to hash it.
-  return (ctx_hash * 3) + static_cast<size_t>(ctx.type_id);
-}
-
-}  // BASE_HASH_NAMESPACE
diff --git a/base/trace_event/memory_profiler_allocation_context.h b/base/trace_event/memory_profiler_allocation_context.h
deleted file mode 100644
index 9063663..0000000
--- a/base/trace_event/memory_profiler_allocation_context.h
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_CONTEXT_H_
-#define BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_CONTEXT_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/base_export.h"
-#include "base/trace_event/trace_event_impl.h"
-
-namespace base {
-namespace trace_event {
-
-class TraceEventMemoryOverhead;
-
-// When heap profiling is enabled, tracing keeps track of the allocation
-// context for each allocation intercepted. It is generated by the
-// |AllocationContextTracker| which keeps stacks of context in TLS.
-// The tracker is initialized lazily.
-
-using StackFrame = const char*;
-
-// A simple stack of |StackFrame| that unlike |std::stack| allows iterating
-// the stack and guards for underflow.
-class BASE_EXPORT AllocationStack {
- public:
-  // Incrementing the iterator iterates up the stack, from bottom (least recent
-  // call) to top (most recent call).
-  using ConstIterator = std::vector<StackFrame>::const_iterator;
-
-  AllocationStack();
-  ~AllocationStack();
-
-  inline ConstIterator bottom() const { return stack_.begin(); }
-  inline ConstIterator top() const { return stack_.end(); }
-
-  inline void push(StackFrame frame) {
-    // Impose a limit on the height to verify that every push is popped, because
-    // in practice the pseudo stack never grows higher than ~20 frames.
-    DCHECK_LT(stack_.size(), 128u);
-    stack_.push_back(frame);
-  }
-
-  inline void pop(StackFrame frame) {
-    if (stack_.empty())
-      return;
-
-    // Assert that pushes and pops are nested correctly.
-    // This DCHECK can be hit if some TRACE_EVENT macro is unbalanced
-    // (a TRACE_EVENT_END* call without a corresponding TRACE_EVENT_BEGIN).
-    DCHECK_EQ(frame, stack_.back())
-        << "Encountered an unmatched TRACE_EVENT_END";
-
-    stack_.pop_back();
-  }
-
- private:
-  std::vector<StackFrame> stack_;
-
-  DISALLOW_COPY_AND_ASSIGN(AllocationStack);
-};
-
-// The backtrace in the allocation context is a snapshot of the stack. For now,
-// this is the pseudo stack where frames are created by trace event macros. In
-// the future, we might add the option to use the native call stack. In that
-// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
-// have different implementations that can be selected by a compile time flag.
-
-// The number of stack frames stored in the backtrace is a trade off between
-// memory used for tracing and accuracy. Measurements done on a prototype
-// revealed that:
-//
-// - In 60 percent of the cases, stack depth <= 7.
-// - In 87 percent of the cases, stack depth <= 9.
-// - In 95 percent of the cases, stack depth <= 11.
-//
-// See the design doc (https://goo.gl/4s7v7b) for more details.
-
-struct BASE_EXPORT Backtrace {
-  // Unused backtrace frames are filled with nullptr frames. If the stack is
-  // higher than what can be stored here, the bottom frames are stored. Based
-  // on the data above, a depth of 12 captures the full stack in the vast
-  // majority of the cases.
-  StackFrame frames[12];
-};
-
-bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
-
-// A data structure that allows grouping a set of backtraces in a space-
-// efficient manner by creating a call tree and writing it as a set of (node,
-// parent) pairs. The tree nodes reference both parent and children. The parent
-// is referenced by index into |frames_|. The children are referenced via a map
-// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
-// lookup of a backtrace for deduplication, and a tree for compact storage in
-// the trace log.
-class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
- public:
-  // A node in the call tree.
-  struct FrameNode {
-    FrameNode(StackFrame frame, int parent_frame_index);
-    ~FrameNode();
-
-    StackFrame frame;
-
-    // The index of the parent stack frame in |frames_|, or -1 if there is no
-    // parent frame (when it is at the bottom of the call stack).
-    int parent_frame_index;
-
-    // Indices into |frames_| of frames called from the current frame.
-    std::map<StackFrame, int> children;
-  };
-
-  using ConstIterator = std::vector<FrameNode>::const_iterator;
-
-  StackFrameDeduplicator();
-
-  // Inserts a backtrace and returns the index of its leaf node in |frames_|.
-  // Returns -1 if the backtrace is empty.
-  int Insert(const Backtrace& bt);
-
-  // Iterators over the frame nodes in the call tree.
-  ConstIterator begin() const { return frames_.begin(); }
-  ConstIterator end() const { return frames_.end(); }
-
-  // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
-  // the trace log.
-  void AppendAsTraceFormat(std::string* out) const override;
-  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
-
- private:
-  ~StackFrameDeduplicator() override;
-
-  std::map<StackFrame, int> roots_;
-  std::vector<FrameNode> frames_;
-
-  DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
-};
-
-// The |AllocationContext| is context metadata that is kept for every allocation
-// when heap profiling is enabled. To simplify memory management for
-// bookkeeping, this struct has a fixed size. All |const char*|s here
-// must have static lifetime.
-// TODO(ruuda): Make the default constructor private to avoid accidentally
-// constructing an instance and forgetting to initialize it. Only
-// |AllocationContextTracker| should be able to construct. (And tests.)
-struct BASE_EXPORT AllocationContext {
-  // A type ID is a number that is unique for every C++ type. A type ID is
-  // stored instead of the type name to avoid inflating the binary with type
-  // name strings. There is an out of band lookup table mapping IDs to the type
-  // names. A value of 0 means that the type is not known.
-  using TypeId = uint16_t;
-
-  Backtrace backtrace;
-  TypeId type_id;
-};
-
-bool BASE_EXPORT operator==(const AllocationContext& lhs,
-                            const AllocationContext& rhs);
-
-// The allocation context tracker keeps track of thread-local context for heap
-// profiling. It includes a pseudo stack of trace events. On every allocation
-// the tracker provides a snapshot of its context in the form of an
-// |AllocationContext| that is to be stored together with the allocation
-// details.
-class BASE_EXPORT AllocationContextTracker {
- public:
-  // Globally enables capturing allocation context.
-  // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
-  // Or at least have something that guards agains enable -> disable -> enable?
-  static void SetCaptureEnabled(bool enabled);
-
-  // Returns whether capturing allocation context is enabled globally.
-  inline static bool capture_enabled() {
-    // A little lag after heap profiling is enabled or disabled is fine, it is
-    // more important that the check is as cheap as possible when capturing is
-    // not enabled, so do not issue a memory barrier in the fast path.
-    if (subtle::NoBarrier_Load(&capture_enabled_) == 0)
-        return false;
-
-    // In the slow path, an acquire load is required to pair with the release
-    // store in |SetCaptureEnabled|. This is to ensure that the TLS slot for
-    // the thread-local allocation context tracker has been initialized if
-    // |capture_enabled| returns true.
-    return subtle::Acquire_Load(&capture_enabled_) != 0;
-  }
-
-  // Pushes a frame onto the thread-local pseudo stack.
-  static void PushPseudoStackFrame(StackFrame frame);
-
-  // Pops a frame from the thread-local pseudo stack.
-  static void PopPseudoStackFrame(StackFrame frame);
-
-  // Returns a snapshot of the current thread-local context.
-  static AllocationContext GetContextSnapshot();
-
-  ~AllocationContextTracker();
-
- private:
-  AllocationContextTracker();
-
-  static AllocationContextTracker* GetThreadLocalTracker();
-
-  static subtle::Atomic32 capture_enabled_;
-
-  // The pseudo stack where frames are |TRACE_EVENT| names.
-  AllocationStack pseudo_stack_;
-
-  DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
-};
-
-}  // namespace trace_event
-}  // namespace base
-
-namespace BASE_HASH_NAMESPACE {
-
-template <>
-struct hash<base::trace_event::Backtrace> {
-  size_t operator()(const base::trace_event::Backtrace& backtrace) const;
-};
-
-template <>
-struct hash<base::trace_event::AllocationContext> {
-  size_t operator()(const base::trace_event::AllocationContext& context) const;
-};
-
-}  // BASE_HASH_NAMESPACE
-
-#endif  // BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 4713311..d83d65bf 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -5,6 +5,18 @@
   'variables': {
     'trace_event_sources' : [
       'trace_event/common/trace_event_common.h',
+      'trace_event/heap_profiler_allocation_context.cc',
+      'trace_event/heap_profiler_allocation_context.h',
+      'trace_event/heap_profiler_allocation_context_tracker.cc',
+      'trace_event/heap_profiler_allocation_context_tracker.h',
+      'trace_event/heap_profiler_allocation_register.cc',
+      'trace_event/heap_profiler_allocation_register_posix.cc',
+      'trace_event/heap_profiler_allocation_register_win.cc',
+      'trace_event/heap_profiler_allocation_register.h',
+      'trace_event/heap_profiler_heap_dump_writer.cc',
+      'trace_event/heap_profiler_heap_dump_writer.h',
+      'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator.h',
       'trace_event/java_heap_dump_provider_android.cc',
       'trace_event/java_heap_dump_provider_android.h',
       'trace_event/memory_allocator_dump.cc',
@@ -18,14 +30,6 @@
       'trace_event/memory_dump_request_args.h',
       'trace_event/memory_dump_session_state.cc',
       'trace_event/memory_dump_session_state.h',
-      'trace_event/memory_profiler_allocation_context.cc',
-      'trace_event/memory_profiler_allocation_context.h',
-      'trace_event/memory_profiler_allocation_register.cc',
-      'trace_event/memory_profiler_allocation_register_posix.cc',
-      'trace_event/memory_profiler_allocation_register_win.cc',
-      'trace_event/memory_profiler_allocation_register.h',
-      'trace_event/memory_profiler_heap_dump_writer.cc',
-      'trace_event/memory_profiler_heap_dump_writer.h',
       'trace_event/process_memory_dump.cc',
       'trace_event/process_memory_dump.h',
       'trace_event/process_memory_maps.cc',
@@ -64,11 +68,12 @@
       'trace_event/winheap_dump_provider_win.h',
     ],
     'trace_event_test_sources' : [
+      'trace_event/heap_profiler_allocation_context_tracker_unittest.cc',
+      'trace_event/heap_profiler_allocation_register_unittest.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
       'trace_event/java_heap_dump_provider_android_unittest.cc',
       'trace_event/memory_allocator_dump_unittest.cc',
       'trace_event/memory_dump_manager_unittest.cc',
-      'trace_event/memory_profiler_allocation_context_unittest.cc',
-      'trace_event/memory_profiler_allocation_register_unittest.cc',
       'trace_event/process_memory_dump_unittest.cc',
       'trace_event/process_memory_totals_dump_provider_unittest.cc',
       'trace_event/trace_config_memory_test_util.h',
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index d9a7e3b..31dda00a 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -26,9 +26,9 @@
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_buffer.h"
 #include "base/trace_event/trace_event.h"
diff --git a/build/common.gypi b/build/common.gypi
index 9f2f91ad..df6ba204 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1987,6 +1987,13 @@
           ['asan==1 or syzyasan==1', {
             'win_use_allocator_shim%': 0,
           }],
+          # The AddressSanitizer build should be a console program as it prints
+          # out stuff on stderr.
+          ['asan==1', {
+            'win_console_app%': 1,
+          }, {
+            'win_console_app%': 0,
+          }],
           ['syzyasan==1', {
             'kasko%': 1,
           }],
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 104001af..ab96da61 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -11,6 +11,14 @@
 import("//chrome/chrome_repack_locales.gni")
 import("//chrome/version.gni")
 
+declare_args() {
+  # If true, builds as a console app (rather than a windowed app), which allows
+  # logging to be printed to the user. This will cause a terminal window to pop
+  # up when Chrome is not run from the command line, so should only be used for
+  # development. Only has an effect on Windows builds.
+  win_console_app = false
+}
+
 if (is_android) {
   import("//build/config/android/rules.gni")
 }
@@ -40,6 +48,12 @@
       ":chrome_initial",
     ]
   }
+
+  # The AddressSanitizer build should be a console program as it prints out
+  # stuff on stderr.
+  if (is_asan) {
+    win_console_app = true
+  }
 }
 
 if (!is_android) {
@@ -154,9 +168,11 @@
         "wintrust.lib",
         "crypt32.lib",
       ]
-      if (!is_asan) {
-        # Set /SUBSYSTEM:WINDOWS for chrome.exe itself, except for the
-        # AddressSanitizer build where console output is important.
+      if (win_console_app) {
+        defines += [ "WIN_CONSOLE_APP" ]
+      } else {
+        # Set /SUBSYSTEM:WINDOWS for chrome.exe itself, unless a console build
+        # has been requested.
         configs -= [ "//build/config/win:console" ]
         configs += [ "//build/config/win:windowed" ]
       }
diff --git a/chrome/VERSION b/chrome/VERSION
index 50c1ed06..260ff22 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=49
 MINOR=0
-BUILD=2565
+BUILD=2566
 PATCH=0
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index a5f8ee1..e3e1754 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -123,11 +123,9 @@
 
 }  // namespace
 
-#if !defined(ADDRESS_SANITIZER)
+#if !defined(WIN_CONSOLE_APP)
 int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
 #else
-// The AddressSanitizer build should be a console program as it prints out stuff
-// on stderr.
 int main() {
   HINSTANCE instance = GetModuleHandle(NULL);
 #endif
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index 22fe77aa..37e7d34 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -45,7 +45,7 @@
 }
 
 void PasswordUIViewAndroid::SetPasswordList(
-    const ScopedVector<autofill::PasswordForm>& password_list,
+    const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
     bool show_passwords) {
   // Android just ignores the |show_passwords| argument.
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -57,7 +57,8 @@
 }
 
 void PasswordUIViewAndroid::SetPasswordExceptionList(
-    const ScopedVector<autofill::PasswordForm>& password_exception_list) {
+    const std::vector<scoped_ptr<autofill::PasswordForm>>&
+        password_exception_list) {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> ui_controller = weak_java_ui_controller_.get(env);
   if (!ui_controller.is_null()) {
diff --git a/chrome/browser/android/password_ui_view_android.h b/chrome/browser/android/password_ui_view_android.h
index 50fed628..ffbd2ee 100644
--- a/chrome/browser/android/password_ui_view_android.h
+++ b/chrome/browser/android/password_ui_view_android.h
@@ -31,10 +31,11 @@
       const std::string& username,
       const base::string16& password_value) override;
   void SetPasswordList(
-      const ScopedVector<autofill::PasswordForm>& password_list,
+      const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
       bool show_passwords) override;
-  void SetPasswordExceptionList(const ScopedVector<autofill::PasswordForm>&
-                                    password_exception_list) override;
+  void SetPasswordExceptionList(
+      const std::vector<scoped_ptr<autofill::PasswordForm>>&
+          password_exception_list) override;
 
   // Calls from Java.
   base::android::ScopedJavaLocalRef<jobject> GetSavedPasswordEntry(
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index d786adb..3f15d3b 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -148,7 +148,7 @@
 }
 
 void PasswordsPrivateDelegateImpl::SetPasswordList(
-    const ScopedVector<autofill::PasswordForm>& password_list,
+    const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
     bool show_passwords) {
   // Rebuild |login_pair_to_index_map_| so that it reflects the contents of the
   // new list.
@@ -162,7 +162,7 @@
 
   // Now, create a list of PasswordUiEntry objects to send to observers.
   current_entries_.clear();
-  for (const autofill::PasswordForm* form : password_list) {
+  for (const auto& form : password_list) {
     linked_ptr<api::passwords_private::PasswordUiEntry> entry(
         new api::passwords_private::PasswordUiEntry);
     entry->login_pair.origin_url =
@@ -192,7 +192,8 @@
 }
 
 void PasswordsPrivateDelegateImpl::SetPasswordExceptionList(
-    const ScopedVector<autofill::PasswordForm>& password_exception_list) {
+    const std::vector<scoped_ptr<autofill::PasswordForm>>&
+        password_exception_list) {
   // Rebuild |exception_url_to_index_map_| so that it reflects the contents of
   // the new list.
   exception_url_to_index_map_.clear();
@@ -204,7 +205,7 @@
 
   // Now, create a list of exceptions to send to observers.
   current_exceptions_.clear();
-  for (const autofill::PasswordForm* form : password_exception_list) {
+  for (const auto& form : password_exception_list) {
     current_exceptions_.push_back(
         password_manager::GetHumanReadableOrigin(*form, languages_));
   }
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
index 63207cb..a3aa82b 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
@@ -53,10 +53,11 @@
       const std::string& username,
       const base::string16& plaintext_password) override;
   void SetPasswordList(
-      const ScopedVector<autofill::PasswordForm>& password_list,
+      const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
       bool show_passwords) override;
-  void SetPasswordExceptionList(const ScopedVector<autofill::PasswordForm>&
-      password_exception_list) override;
+  void SetPasswordExceptionList(
+      const std::vector<scoped_ptr<autofill::PasswordForm>>&
+          password_exception_list) override;
 #if !defined(OS_ANDROID)
   gfx::NativeWindow GetNativeWindow() const override;
 #endif
diff --git a/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.css b/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.css
index e4ec546..1133812 100644
--- a/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.css
+++ b/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.css
@@ -17,6 +17,16 @@
   color: rgb(20, 20, 20);
 }
 
+paper-ripple {
+  /* Allowing the ripple to capture pointer events prevents a focus rectangle
+   * for showing up for clicks, while still allowing it with tab-navigation.
+   * This undoes a paper-ripple bugfix aimed at non-Chrome browsers.
+   * TODO(tsergeant): Improve focus in viewer-bookmark so this can be removed
+   * (https://crbug.com/5448190).
+   */
+  pointer-events: auto;
+}
+
 #title {
   overflow: hidden;
   text-overflow: ellipsis;
diff --git a/chrome/browser/ui/passwords/password_manager_presenter.cc b/chrome/browser/ui/passwords/password_manager_presenter.cc
index 5769971..914a7a7 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter.cc
@@ -23,6 +23,7 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/password_manager/core/browser/affiliation_utils.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/password_manager/sync/browser/password_sync_util.h"
 #include "content/public/browser/user_metrics.h"
@@ -186,7 +187,7 @@
     NOTREACHED();
     return NULL;
   }
-  return password_list_[index];
+  return password_list_[index].get();
 }
 
 const autofill::PasswordForm* PasswordManagerPresenter::GetPasswordException(
@@ -197,7 +198,7 @@
     NOTREACHED();
     return NULL;
   }
-  return password_exception_list_[index];
+  return password_exception_list_[index].get();
 }
 
 void PasswordManagerPresenter::SetPasswordList() {
@@ -240,7 +241,8 @@
 
 void PasswordManagerPresenter::PasswordListPopulater::OnGetPasswordStoreResults(
     ScopedVector<autofill::PasswordForm> results) {
-  page_->password_list_.swap(results);
+  page_->password_list_ =
+      password_manager_util::ConvertScopedVector(results.Pass());
   page_->SetPasswordList();
 }
 
@@ -261,6 +263,7 @@
 
 void PasswordManagerPresenter::PasswordExceptionListPopulater::
     OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) {
-  page_->password_exception_list_.swap(results);
+  page_->password_exception_list_ =
+      password_manager_util::ConvertScopedVector(results.Pass());
   page_->SetPasswordExceptionList();
 }
diff --git a/chrome/browser/ui/passwords/password_manager_presenter.h b/chrome/browser/ui/passwords/password_manager_presenter.h
index fcb3b696..fce6210 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.h
+++ b/chrome/browser/ui/passwords/password_manager_presenter.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/prefs/pref_member.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -111,8 +112,8 @@
   PasswordListPopulater populater_;
   PasswordExceptionListPopulater exception_populater_;
 
-  ScopedVector<autofill::PasswordForm> password_list_;
-  ScopedVector<autofill::PasswordForm> password_exception_list_;
+  std::vector<scoped_ptr<autofill::PasswordForm>> password_list_;
+  std::vector<scoped_ptr<autofill::PasswordForm>> password_exception_list_;
 
   // Whether to show stored passwords or not.
   BooleanPrefMember show_passwords_;
diff --git a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
index 8d2417c..a2ebe32 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
@@ -31,9 +31,10 @@
   MOCK_METHOD4(ShowPassword, void(
       size_t, const std::string&, const std::string&, const base::string16&));
   MOCK_METHOD2(SetPasswordList,
-               void(const ScopedVector<autofill::PasswordForm>&, bool));
+               void(const std::vector<scoped_ptr<autofill::PasswordForm>>&,
+                    bool));
   MOCK_METHOD1(SetPasswordExceptionList,
-               void(const ScopedVector<autofill::PasswordForm>&));
+               void(const std::vector<scoped_ptr<autofill::PasswordForm>>&));
   PasswordManagerPresenter* GetPasswordManagerPresenter() {
     return &password_manager_presenter_;
   }
@@ -81,21 +82,21 @@
     const GURL& origin,
     const std::string& user_name,
     const std::string& password) {
-  autofill::PasswordForm* form = new autofill::PasswordForm();
+  scoped_ptr<autofill::PasswordForm> form(new autofill::PasswordForm());
   form->origin = origin;
   form->username_element = base::ASCIIToUTF16("Email");
   form->username_value = base::ASCIIToUTF16(user_name);
   form->password_element = base::ASCIIToUTF16("Passwd");
   form->password_value = base::ASCIIToUTF16(password);
-  mock_controller_->GetPasswordManagerPresenter()->password_list_
-      .push_back(form);
+  mock_controller_->GetPasswordManagerPresenter()->password_list_.push_back(
+      form.Pass());
 }
 
 void PasswordManagerPresenterTest::AddPasswordException(const GURL& origin) {
-  autofill::PasswordForm* form = new autofill::PasswordForm();
+  scoped_ptr<autofill::PasswordForm> form(new autofill::PasswordForm());
   form->origin = origin;
-  mock_controller_->GetPasswordManagerPresenter()->password_exception_list_
-      .push_back(form);
+  mock_controller_->GetPasswordManagerPresenter()
+      ->password_exception_list_.push_back(form.Pass());
 }
 
 void PasswordManagerPresenterTest::UpdateLists() {
@@ -109,44 +110,52 @@
   EXPECT_CALL(
       *GetUIController(),
       SetPasswordList(
-          Property(&ScopedVector<autofill::PasswordForm>::size, Eq(0u)),
+          Property(&std::vector<scoped_ptr<autofill::PasswordForm>>::size,
+                   Eq(0u)),
           testing::_));
-  EXPECT_CALL(*GetUIController(),
-              SetPasswordExceptionList(Property(
-                  &ScopedVector<autofill::PasswordForm>::size, Eq(0u))));
+  EXPECT_CALL(
+      *GetUIController(),
+      SetPasswordExceptionList(Property(
+          &std::vector<scoped_ptr<autofill::PasswordForm>>::size, Eq(0u))));
   UpdateLists();
   GURL pass_origin("http://abc1.com");
   AddPasswordEntry(pass_origin, "test@gmail.com", "test");
   EXPECT_CALL(
       *GetUIController(),
       SetPasswordList(
-          Property(&ScopedVector<autofill::PasswordForm>::size, Eq(1u)),
+          Property(&std::vector<scoped_ptr<autofill::PasswordForm>>::size,
+                   Eq(1u)),
           testing::_));
-  EXPECT_CALL(*GetUIController(),
-              SetPasswordExceptionList(Property(
-                  &ScopedVector<autofill::PasswordForm>::size, Eq(0u))));
+  EXPECT_CALL(
+      *GetUIController(),
+      SetPasswordExceptionList(Property(
+          &std::vector<scoped_ptr<autofill::PasswordForm>>::size, Eq(0u))));
   UpdateLists();
   GURL except_origin("http://abc2.com");
   AddPasswordException(except_origin);
   EXPECT_CALL(
       *GetUIController(),
       SetPasswordList(
-          Property(&ScopedVector<autofill::PasswordForm>::size, Eq(1u)),
+          Property(&std::vector<scoped_ptr<autofill::PasswordForm>>::size,
+                   Eq(1u)),
           testing::_));
-  EXPECT_CALL(*GetUIController(),
-              SetPasswordExceptionList(Property(
-                  &ScopedVector<autofill::PasswordForm>::size, Eq(1u))));
+  EXPECT_CALL(
+      *GetUIController(),
+      SetPasswordExceptionList(Property(
+          &std::vector<scoped_ptr<autofill::PasswordForm>>::size, Eq(1u))));
   UpdateLists();
   GURL pass_origin2("http://example.com");
   AddPasswordEntry(pass_origin2, "test@gmail.com", "test");
   EXPECT_CALL(
       *GetUIController(),
       SetPasswordList(
-          Property(&ScopedVector<autofill::PasswordForm>::size, Eq(2u)),
+          Property(&std::vector<scoped_ptr<autofill::PasswordForm>>::size,
+                   Eq(2u)),
           testing::_));
-  EXPECT_CALL(*GetUIController(),
-              SetPasswordExceptionList(Property(
-                  &ScopedVector<autofill::PasswordForm>::size, Eq(1u))));
+  EXPECT_CALL(
+      *GetUIController(),
+      SetPasswordExceptionList(Property(
+          &std::vector<scoped_ptr<autofill::PasswordForm>>::size, Eq(1u))));
   UpdateLists();
 }
 
diff --git a/chrome/browser/ui/passwords/password_ui_view.h b/chrome/browser/ui/passwords/password_ui_view.h
index 92f1b2c..4299cfa 100644
--- a/chrome/browser/ui/passwords/password_ui_view.h
+++ b/chrome/browser/ui/passwords/password_ui_view.h
@@ -6,8 +6,9 @@
 #define CHROME_BROWSER_UI_PASSWORDS_PASSWORD_UI_VIEW_H_
 
 #include <string>
+#include <vector>
 
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace autofill {
@@ -41,13 +42,14 @@
   // |password_list| the list of saved password entries.
   // |show_passwords| true if the passwords should be shown in the UI.
   virtual void SetPasswordList(
-      const ScopedVector<autofill::PasswordForm>& password_list,
+      const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
       bool show_passwords) = 0;
 
   // Updates the list of password exceptions in the UI.
   // |password_exception_list| The list of saved password exceptions.
   virtual void SetPasswordExceptionList(
-      const ScopedVector<autofill::PasswordForm>& password_exception_list) = 0;
+      const std::vector<scoped_ptr<autofill::PasswordForm>>&
+          password_exception_list) = 0;
 #if !defined(OS_ANDROID)
   // Returns the top level NativeWindow for the view.
   virtual gfx::NativeWindow GetNativeWindow() const = 0;
diff --git a/chrome/browser/ui/webui/gcm_internals_ui.cc b/chrome/browser/ui/webui/gcm_internals_ui.cc
index 79e45e8..0529985b 100644
--- a/chrome/browser/ui/webui/gcm_internals_ui.cc
+++ b/chrome/browser/ui/webui/gcm_internals_ui.cc
@@ -8,11 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/format_macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
@@ -20,6 +16,7 @@
 #include "components/gcm_driver/gcm_client.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/gcm_driver/gcm_internals_constants.h"
+#include "components/gcm_driver/gcm_internals_helper.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -29,85 +26,6 @@
 
 namespace {
 
-void SetCheckinInfo(
-    const std::vector<gcm::CheckinActivity>& checkins,
-    base::ListValue* checkin_info) {
-  std::vector<gcm::CheckinActivity>::const_iterator it = checkins.begin();
-  for (; it < checkins.end(); ++it) {
-    base::ListValue* row = new base::ListValue();
-    checkin_info->Append(row);
-
-    row->AppendDouble(it->time.ToJsTime());
-    row->AppendString(it->event);
-    row->AppendString(it->details);
-  }
-}
-
-void SetConnectionInfo(
-    const std::vector<gcm::ConnectionActivity>& connections,
-    base::ListValue* connection_info) {
-  std::vector<gcm::ConnectionActivity>::const_iterator it = connections.begin();
-  for (; it < connections.end(); ++it) {
-    base::ListValue* row = new base::ListValue();
-    connection_info->Append(row);
-
-    row->AppendDouble(it->time.ToJsTime());
-    row->AppendString(it->event);
-    row->AppendString(it->details);
-  }
-}
-
-void SetRegistrationInfo(
-    const std::vector<gcm::RegistrationActivity>& registrations,
-    base::ListValue* registration_info) {
-  std::vector<gcm::RegistrationActivity>::const_iterator it =
-      registrations.begin();
-  for (; it < registrations.end(); ++it) {
-    base::ListValue* row = new base::ListValue();
-    registration_info->Append(row);
-
-    row->AppendDouble(it->time.ToJsTime());
-    row->AppendString(it->app_id);
-    row->AppendString(it->source);
-    row->AppendString(it->event);
-    row->AppendString(it->details);
-  }
-}
-
-void SetReceivingInfo(
-    const std::vector<gcm::ReceivingActivity>& receives,
-    base::ListValue* receive_info) {
-  std::vector<gcm::ReceivingActivity>::const_iterator it = receives.begin();
-  for (; it < receives.end(); ++it) {
-    base::ListValue* row = new base::ListValue();
-    receive_info->Append(row);
-
-    row->AppendDouble(it->time.ToJsTime());
-    row->AppendString(it->app_id);
-    row->AppendString(it->from);
-    row->AppendString(base::IntToString(it->message_byte_size));
-    row->AppendString(it->event);
-    row->AppendString(it->details);
-  }
-}
-
-void SetSendingInfo(
-    const std::vector<gcm::SendingActivity>& sends,
-    base::ListValue* send_info) {
-  std::vector<gcm::SendingActivity>::const_iterator it = sends.begin();
-  for (; it < sends.end(); ++it) {
-    base::ListValue* row = new base::ListValue();
-    send_info->Append(row);
-
-    row->AppendDouble(it->time.ToJsTime());
-    row->AppendString(it->app_id);
-    row->AppendString(it->receiver_id);
-    row->AppendString(it->message_id);
-    row->AppendString(it->event);
-    row->AppendString(it->details);
-  }
-}
-
 // Class acting as a controller of the chrome://gcm-internals WebUI.
 class GcmInternalsUIMessageHandler : public content::WebUIMessageHandler {
  public:
@@ -150,66 +68,8 @@
     gcm::GCMProfileService* profile_service,
     const gcm::GCMClient::GCMStatistics* stats) const {
   base::DictionaryValue results;
-  base::DictionaryValue* device_info = new base::DictionaryValue();
-  results.Set(gcm_driver::kDeviceInfo, device_info);
-
-  device_info->SetBoolean(gcm_driver::kProfileServiceCreated,
-                          profile_service != NULL);
-  device_info->SetBoolean(
-      gcm_driver::kGcmEnabled,
-      gcm::GCMProfileService::IsGCMEnabled(profile->GetPrefs()));
-  if (stats) {
-    results.SetBoolean(gcm_driver::kIsRecording, stats->is_recording);
-    device_info->SetBoolean(gcm_driver::kGcmClientCreated,
-                            stats->gcm_client_created);
-    device_info->SetString(gcm_driver::kGcmClientState,
-                           stats->gcm_client_state);
-    device_info->SetBoolean(gcm_driver::kConnectionClientCreated,
-                            stats->connection_client_created);
-    device_info->SetString(gcm_driver::kRegisteredAppIds,
-                           base::JoinString(stats->registered_app_ids, ","));
-    if (stats->connection_client_created)
-      device_info->SetString(gcm_driver::kConnectionState,
-                             stats->connection_state);
-    if (stats->android_id > 0) {
-      device_info->SetString(
-          gcm_driver::kAndroidId,
-          base::StringPrintf("0x%" PRIx64, stats->android_id));
-    }
-    device_info->SetInteger(gcm_driver::kSendQueueSize, stats->send_queue_size);
-    device_info->SetInteger(gcm_driver::kResendQueueSize,
-                            stats->resend_queue_size);
-
-    if (stats->recorded_activities.checkin_activities.size() > 0) {
-      base::ListValue* checkin_info = new base::ListValue();
-      results.Set(gcm_driver::kCheckinInfo, checkin_info);
-      SetCheckinInfo(stats->recorded_activities.checkin_activities,
-                     checkin_info);
-    }
-    if (stats->recorded_activities.connection_activities.size() > 0) {
-      base::ListValue* connection_info = new base::ListValue();
-      results.Set(gcm_driver::kConnectionInfo, connection_info);
-      SetConnectionInfo(stats->recorded_activities.connection_activities,
-                        connection_info);
-    }
-    if (stats->recorded_activities.registration_activities.size() > 0) {
-      base::ListValue* registration_info = new base::ListValue();
-      results.Set(gcm_driver::kRegistrationInfo, registration_info);
-      SetRegistrationInfo(stats->recorded_activities.registration_activities,
-                          registration_info);
-    }
-    if (stats->recorded_activities.receiving_activities.size() > 0) {
-      base::ListValue* receive_info = new base::ListValue();
-      results.Set(gcm_driver::kReceiveInfo, receive_info);
-      SetReceivingInfo(stats->recorded_activities.receiving_activities,
-                       receive_info);
-    }
-    if (stats->recorded_activities.sending_activities.size() > 0) {
-      base::ListValue* send_info = new base::ListValue();
-      results.Set(gcm_driver::kSendInfo, send_info);
-      SetSendingInfo(stats->recorded_activities.sending_activities, send_info);
-    }
-  }
+  gcm_driver::SetGCMInternalsInfo(stats, profile_service, profile->GetPrefs(),
+                                  &results);
   web_ui()->CallJavascriptFunction(gcm_driver::kSetGcmInternalsInfo, results);
 }
 
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
index 216a008..23055dd 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -216,12 +216,12 @@
 }
 
 void PasswordManagerHandler::SetPasswordList(
-    const ScopedVector<autofill::PasswordForm>& password_list,
+    const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
     bool show_passwords) {
   base::ListValue entries;
   languages_ = GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
   base::string16 placeholder(base::ASCIIToUTF16("        "));
-  for (const autofill::PasswordForm* saved_password : password_list) {
+  for (const auto& saved_password : password_list) {
     scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
     CopyOriginInfoOfPasswordForm(*saved_password, languages_, entry.get());
 
@@ -250,9 +250,10 @@
 }
 
 void PasswordManagerHandler::SetPasswordExceptionList(
-    const ScopedVector<autofill::PasswordForm>& password_exception_list) {
+    const std::vector<scoped_ptr<autofill::PasswordForm>>&
+        password_exception_list) {
   base::ListValue entries;
-  for (const autofill::PasswordForm* exception : password_exception_list) {
+  for (const auto& exception : password_exception_list) {
     scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
     CopyOriginInfoOfPasswordForm(*exception, languages_, entry.get());
     entries.Append(entry.release());
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.h b/chrome/browser/ui/webui/options/password_manager_handler.h
index a08ecbe2..5befa1b 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.h
+++ b/chrome/browser/ui/webui/options/password_manager_handler.h
@@ -35,10 +35,11 @@
       const std::string& username,
       const base::string16& password_value) override;
   void SetPasswordList(
-      const ScopedVector<autofill::PasswordForm>& password_list,
+      const std::vector<scoped_ptr<autofill::PasswordForm>>& password_list,
       bool show_passwords) override;
-  void SetPasswordExceptionList(const ScopedVector<autofill::PasswordForm>&
-                                    password_exception_list) override;
+  void SetPasswordExceptionList(
+      const std::vector<scoped_ptr<autofill::PasswordForm>>&
+          password_exception_list) override;
 #if !defined(OS_ANDROID)
   gfx::NativeWindow GetNativeWindow() const override;
 #endif
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index a107569..d02673f 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -109,6 +109,9 @@
                 'kasko_dll',
               ],
             }],
+            ['win_console_app==1', {
+              'defines': ['WIN_CONSOLE_APP'],
+            }],
           ],
         }],
         ['OS == "android"', {
@@ -450,9 +453,9 @@
                 'crypt32.lib'
               ],
               'conditions': [
-                ['asan==0', {
-                  # Set /SUBSYSTEM:WINDOWS for chrome.exe itself, except for the
-                  # AddressSanitizer build where console output is important.
+                ['win_console_app==0', {
+                  # Set /SUBSYSTEM:WINDOWS for chrome.exe itself, unless a
+                  # console build has been requested.
                   'SubSystem': '2',
                 }],
               ],
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index f6d85d7..97b4b93 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7633.0.0
\ No newline at end of file
+7644.0.0
\ No newline at end of file
diff --git a/components/drive/search_metadata.cc b/components/drive/search_metadata.cc
index fcc3531..1e316f0 100644
--- a/components/drive/search_metadata.cc
+++ b/components/drive/search_metadata.cc
@@ -54,44 +54,15 @@
 }
 
 struct ResultCandidateComparator {
-  bool operator()(const ResultCandidate* a, const ResultCandidate* b) const {
+  bool operator()(const scoped_ptr<ResultCandidate>& a,
+                  const scoped_ptr<ResultCandidate>& b) const {
     return CompareByTimestamp(a->entry, b->entry);
   }
 };
 
-// A wrapper of std::priority_queue which deals with pointers of values.
-template<typename T, typename Compare>
-class ScopedPriorityQueue {
- public:
-  ScopedPriorityQueue() {}
-
-  ~ScopedPriorityQueue() {
-    while (!empty())
-      pop();
-  }
-
-  bool empty() const { return queue_.empty(); }
-
-  size_t size() const { return queue_.size(); }
-
-  const T* top() const { return queue_.top(); }
-
-  void push(T* x) { queue_.push(x); }
-
-  void pop() {
-    // Keep top alive for the pop() call so that debug checks can access
-    // underlying data (e.g. validating heap property of the priority queue
-    // will call the comparator).
-    T* saved_top = queue_.top();
-    queue_.pop();
-    delete saved_top;
-  }
-
- private:
-  std::priority_queue<T*, std::vector<T*>, Compare> queue_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedPriorityQueue);
-};
+typedef std::priority_queue<scoped_ptr<ResultCandidate>,
+                            std::vector<scoped_ptr<ResultCandidate>>,
+                            ResultCandidateComparator> ResultCandidateQueue;
 
 // Classifies the given entry as hidden if it's not under specific directories.
 class HiddenEntryClassifier {
@@ -154,8 +125,7 @@
     const SearchMetadataPredicate& predicate,
     size_t at_most_num_matches,
     HiddenEntryClassifier* hidden_entry_classifier,
-    ScopedPriorityQueue<ResultCandidate, ResultCandidateComparator>*
-        result_candidates) {
+    ResultCandidateQueue* result_candidates) {
   DCHECK_GE(at_most_num_matches, result_candidates->size());
 
   const ResourceEntry& entry = it->GetValue();
@@ -184,7 +154,8 @@
   // Make space for |entry| when appropriate.
   if (result_candidates->size() == at_most_num_matches)
     result_candidates->pop();
-  result_candidates->push(new ResultCandidate(it->GetID(), entry, highlighted));
+  result_candidates->push(make_scoped_ptr(
+      new ResultCandidate(it->GetID(), entry, highlighted)));
   return FILE_ERROR_OK;
 }
 
@@ -194,8 +165,7 @@
                                        const SearchMetadataPredicate& predicate,
                                        int at_most_num_matches,
                                        MetadataSearchResultVector* results) {
-  ScopedPriorityQueue<ResultCandidate,
-                      ResultCandidateComparator> result_candidates;
+  ResultCandidateQueue result_candidates;
 
   // Prepare data structure for searching.
   std::vector<base::string16> keywords =
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi
index 7ac49c9..9c5bb23d 100644
--- a/components/gcm_driver.gypi
+++ b/components/gcm_driver.gypi
@@ -81,6 +81,8 @@
         'gcm_driver/gcm_driver_desktop.h',
         'gcm_driver/gcm_internals_constants.cc',
         'gcm_driver/gcm_internals_constants.h',
+        'gcm_driver/gcm_internals_helper.cc',
+        'gcm_driver/gcm_internals_helper.h',
         'gcm_driver/gcm_profile_service.cc',
         'gcm_driver/gcm_profile_service.h',
         'gcm_driver/gcm_stats_recorder_impl.cc',
diff --git a/components/gcm_driver/BUILD.gn b/components/gcm_driver/BUILD.gn
index 2e852433..46c35eb 100644
--- a/components/gcm_driver/BUILD.gn
+++ b/components/gcm_driver/BUILD.gn
@@ -45,6 +45,8 @@
     "gcm_driver_desktop.h",
     "gcm_internals_constants.cc",
     "gcm_internals_constants.h",
+    "gcm_internals_helper.cc",
+    "gcm_internals_helper.h",
     "gcm_profile_service.cc",
     "gcm_profile_service.h",
     "gcm_stats_recorder_impl.cc",
diff --git a/components/gcm_driver/gcm_internals_helper.cc b/components/gcm_driver/gcm_internals_helper.cc
new file mode 100644
index 0000000..c66d3d7
--- /dev/null
+++ b/components/gcm_driver/gcm_internals_helper.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/gcm_driver/gcm_internals_helper.h"
+
+#include "base/format_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/gcm_driver/gcm_activity.h"
+#include "components/gcm_driver/gcm_internals_constants.h"
+#include "components/gcm_driver/gcm_profile_service.h"
+
+namespace gcm_driver {
+
+namespace {
+
+void SetCheckinInfo(const std::vector<gcm::CheckinActivity>& checkins,
+                    base::ListValue* checkin_info) {
+  for (const gcm::CheckinActivity& checkin : checkins) {
+        base::ListValue* row = new base::ListValue();
+    checkin_info->Append(row);
+
+    row->AppendDouble(checkin.time.ToJsTime());
+    row->AppendString(checkin.event);
+    row->AppendString(checkin.details);
+  }
+}
+
+void SetConnectionInfo(const std::vector<gcm::ConnectionActivity>& connections,
+                       base::ListValue* connection_info) {
+  for (const gcm::ConnectionActivity& connection : connections) {
+    base::ListValue* row = new base::ListValue();
+    connection_info->Append(row);
+
+    row->AppendDouble(connection.time.ToJsTime());
+    row->AppendString(connection.event);
+    row->AppendString(connection.details);
+  }
+}
+
+void SetRegistrationInfo(
+    const std::vector<gcm::RegistrationActivity>& registrations,
+    base::ListValue* registration_info) {
+  for (const gcm::RegistrationActivity& registration : registrations) {
+    base::ListValue* row = new base::ListValue();
+    registration_info->Append(row);
+
+    row->AppendDouble(registration.time.ToJsTime());
+    row->AppendString(registration.app_id);
+    row->AppendString(registration.source);
+    row->AppendString(registration.event);
+    row->AppendString(registration.details);
+  }
+}
+
+void SetReceivingInfo(const std::vector<gcm::ReceivingActivity>& receives,
+                      base::ListValue* receive_info) {
+  for (const gcm::ReceivingActivity& receive : receives) {
+    base::ListValue* row = new base::ListValue();
+    receive_info->Append(row);
+
+    row->AppendDouble(receive.time.ToJsTime());
+    row->AppendString(receive.app_id);
+    row->AppendString(receive.from);
+    row->AppendString(base::IntToString(receive.message_byte_size));
+    row->AppendString(receive.event);
+    row->AppendString(receive.details);
+  }
+}
+
+void SetSendingInfo(const std::vector<gcm::SendingActivity>& sends,
+                    base::ListValue* send_info) {
+  for (const gcm::SendingActivity& send : sends) {
+    base::ListValue* row = new base::ListValue();
+    send_info->Append(row);
+
+    row->AppendDouble(send.time.ToJsTime());
+    row->AppendString(send.app_id);
+    row->AppendString(send.receiver_id);
+    row->AppendString(send.message_id);
+    row->AppendString(send.event);
+    row->AppendString(send.details);
+  }
+}
+
+}  // namespace
+
+void SetGCMInternalsInfo(const gcm::GCMClient::GCMStatistics* stats,
+                         gcm::GCMProfileService* profile_service,
+                         PrefService* prefs,
+                         base::DictionaryValue* results) {
+  base::DictionaryValue* device_info = new base::DictionaryValue();
+  results->Set(kDeviceInfo, device_info);
+
+  device_info->SetBoolean(kProfileServiceCreated, profile_service != NULL);
+  device_info->SetBoolean(kGcmEnabled,
+                          gcm::GCMProfileService::IsGCMEnabled(prefs));
+  if (stats) {
+    results->SetBoolean(kIsRecording, stats->is_recording);
+    device_info->SetBoolean(kGcmClientCreated, stats->gcm_client_created);
+    device_info->SetString(kGcmClientState, stats->gcm_client_state);
+    device_info->SetBoolean(kConnectionClientCreated,
+                            stats->connection_client_created);
+    device_info->SetString(kRegisteredAppIds,
+                           base::JoinString(stats->registered_app_ids, ","));
+    if (stats->connection_client_created)
+      device_info->SetString(kConnectionState, stats->connection_state);
+    if (stats->android_id > 0) {
+      device_info->SetString(
+          kAndroidId, base::StringPrintf("0x%" PRIx64, stats->android_id));
+    }
+    device_info->SetInteger(kSendQueueSize, stats->send_queue_size);
+    device_info->SetInteger(kResendQueueSize, stats->resend_queue_size);
+
+    if (stats->recorded_activities.checkin_activities.size() > 0) {
+      base::ListValue* checkin_info = new base::ListValue();
+      results->Set(kCheckinInfo, checkin_info);
+      SetCheckinInfo(stats->recorded_activities.checkin_activities,
+                     checkin_info);
+    }
+    if (stats->recorded_activities.connection_activities.size() > 0) {
+      base::ListValue* connection_info = new base::ListValue();
+      results->Set(kConnectionInfo, connection_info);
+      SetConnectionInfo(stats->recorded_activities.connection_activities,
+                        connection_info);
+    }
+    if (stats->recorded_activities.registration_activities.size() > 0) {
+      base::ListValue* registration_info = new base::ListValue();
+      results->Set(kRegistrationInfo, registration_info);
+      SetRegistrationInfo(stats->recorded_activities.registration_activities,
+                          registration_info);
+    }
+    if (stats->recorded_activities.receiving_activities.size() > 0) {
+      base::ListValue* receive_info = new base::ListValue();
+      results->Set(kReceiveInfo, receive_info);
+      SetReceivingInfo(stats->recorded_activities.receiving_activities,
+                       receive_info);
+    }
+    if (stats->recorded_activities.sending_activities.size() > 0) {
+      base::ListValue* send_info = new base::ListValue();
+      results->Set(kSendInfo, send_info);
+      SetSendingInfo(stats->recorded_activities.sending_activities, send_info);
+    }
+  }
+}
+
+}  // namespace gcm_driver
diff --git a/components/gcm_driver/gcm_internals_helper.h b/components/gcm_driver/gcm_internals_helper.h
new file mode 100644
index 0000000..ee89602
--- /dev/null
+++ b/components/gcm_driver/gcm_internals_helper.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_GCM_DRIVER_GCM_INTERNALS_HELPER_H_
+#define COMPONENTS_GCM_DRIVER_GCM_INTERNALS_HELPER_H_
+
+#include <vector>
+
+#include "components/gcm_driver/gcm_client.h"
+
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace gcm {
+class GCMProfileService;
+}
+
+namespace gcm_driver {
+
+// Sets the GCM infos for the gcm-internals WebUI in |results|.
+void SetGCMInternalsInfo(const gcm::GCMClient::GCMStatistics* stats,
+                         gcm::GCMProfileService* profile_service,
+                         PrefService* prefs,
+                         base::DictionaryValue* results);
+
+}  // namespace gcm_driver
+
+#endif  // COMPONENTS_GCM_DRIVER_GCM_INTERNALS_HELPER_H_
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index 6f911ef..7c8ac3f9 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -87,7 +87,7 @@
 
   base::Time visit_time;
   history::RedirectList redirects;
-  for (const auto& row : rows) {
+  for (const history::URLRow& row : rows) {
     observer->OnURLVisited(nullptr, ui::PAGE_TRANSITION_LINK, row, redirects,
                            visit_time);
   }
@@ -3170,7 +3170,7 @@
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("http://cnn.com/intl"));
   urls.push_back(GURL("http://dogtopia.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3185,7 +3185,7 @@
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("https://cnn.com/intl"));
   urls.push_back(GURL("http://cnn.com:567/sports"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3198,7 +3198,7 @@
   urls.push_back(GURL("http://www.cnn.com/us"));
   urls.push_back(GURL("http://cnn.com/intl"));
   urls.push_back(GURL("http://www.dogtopia.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3213,7 +3213,7 @@
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("http://cnn.com/intl"));
   urls.push_back(GURL("http://dogtopia.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3234,7 +3234,7 @@
   urls.push_back(GURL("http://dogtopia.com/"));
   urls.push_back(GURL("http://dogtopia.com/webcam"));
   urls.push_back(GURL("http://www.gardenweb.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3255,7 +3255,7 @@
   urls.push_back(GURL("data:text/plain,Hello%20world%21"));
   urls.push_back(GURL("chrome://memory"));
   urls.push_back(GURL("about:mammon"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3268,7 +3268,7 @@
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("http://cnn.com/intl"));
   urls.push_back(GURL("http://dogtopia.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3292,7 +3292,7 @@
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("http://cnn.com/intl"));
   urls.push_back(GURL("http://dogtopia.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
                            history::SOURCE_BROWSED);
   }
@@ -3306,7 +3306,7 @@
   urls.clear();
   urls.push_back(GURL("http://cnn.com/us"));
   urls.push_back(GURL("http://www.unipresse.com/"));
-  for (const auto& url : urls) {
+  for (const GURL& url : urls) {
     backend_->AddPageVisit(url, base::Time::Now(), 0,
                            ui::PAGE_TRANSITION_CHAIN_END,
                            history::SOURCE_BROWSED);
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 44123a0..1b4bff4 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -74,4 +74,15 @@
   android_credentials->swap(result);
 }
 
+std::vector<scoped_ptr<autofill::PasswordForm>> ConvertScopedVector(
+    ScopedVector<autofill::PasswordForm> old_vector) {
+  std::vector<scoped_ptr<autofill::PasswordForm>> new_vector;
+  new_vector.reserve(old_vector.size());
+  for (auto* form : old_vector) {
+    new_vector.push_back(make_scoped_ptr(form));
+  }
+  old_vector.weak_clear();  // All owned by |new_vector| by now.
+  return new_vector;
+}
+
 }  // namespace password_manager_util
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index ef2517b..3b00570 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -5,8 +5,11 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "ui/gfx/native_widget_types.h"
@@ -42,6 +45,11 @@
 void TrimUsernameOnlyCredentials(
     ScopedVector<autofill::PasswordForm>* android_credentials);
 
+// TODO(crbug.com/555132): Remove this when the migration from ScopedVector is
+// finished for PasswordForm.
+std::vector<scoped_ptr<autofill::PasswordForm>> ConvertScopedVector(
+    ScopedVector<autofill::PasswordForm> old_vector);
+
 }  // namespace password_manager_util
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
diff --git a/content/child/web_memory_dump_provider_adapter.cc b/content/child/web_memory_dump_provider_adapter.cc
index 8666fd09..b0a8a6a 100644
--- a/content/child/web_memory_dump_provider_adapter.cc
+++ b/content/child/web_memory_dump_provider_adapter.cc
@@ -6,8 +6,10 @@
 
 #include "base/lazy_instance.h"
 #include "base/synchronization/lock.h"
-#include "base/trace_event/memory_profiler_allocation_register.h"
-#include "base/trace_event/memory_profiler_heap_dump_writer.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "base/trace_event/trace_event_memory_overhead.h"
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index c7234e82..db37905 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -54,33 +54,6 @@
 
 namespace content {
 
-// Iterate recursively over sub-frames to find one with with a given url.
-WebFrame* FindSubFrameByURL(WebView* web_view, const GURL& url) {
-  if (!web_view->mainFrame())
-    return NULL;
-
-  std::vector<WebFrame*> stack;
-  stack.push_back(web_view->mainFrame());
-
-  while (!stack.empty()) {
-    WebFrame* current_frame = stack.back();
-    stack.pop_back();
-    if (GURL(current_frame->document().url()) == url)
-      return current_frame;
-    WebElementCollection all = current_frame->document().all();
-    for (WebElement element = all.firstItem();
-         !element.isNull(); element = all.nextItem()) {
-      // Check frame tag and iframe tag
-      if (!element.hasHTMLTagName("frame") && !element.hasHTMLTagName("iframe"))
-        continue;
-      WebFrame* sub_frame = WebLocalFrame::fromFrameOwnerElement(element);
-      if (sub_frame)
-        stack.push_back(sub_frame);
-    }
-  }
-  return NULL;
-}
-
 bool HasDocType(const WebDocument& doc) {
   return !doc.doctype().isNull();
 }
@@ -199,6 +172,15 @@
     return GetWebView()->mainFrame();
   }
 
+  WebFrame* FindSubFrameByURL(const GURL& url) {
+    for (WebFrame* frame = GetWebView()->mainFrame(); frame;
+        frame = frame->traverseNext(false)) {
+      if (GURL(frame->document().url()) == url)
+        return frame;
+    }
+    return nullptr;
+  }
+
   // Load web page according to input content and relative URLs within
   // the document.
   void LoadContents(const std::string& contents,
@@ -229,7 +211,7 @@
   // Serialize DOM belonging to a frame with the specified |frame_url|.
   void SerializeDomForURL(const GURL& frame_url) {
     // Find corresponding WebFrame according to frame_url.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), frame_url);
+    WebFrame* web_frame = FindSubFrameByURL(frame_url);
     ASSERT_TRUE(web_frame != NULL);
     WebVector<WebURL> links;
     links.assign(&frame_url, 1);
@@ -248,7 +230,7 @@
 
   void SerializeHTMLDOMWithDocTypeOnRenderer(const GURL& file_url) {
     // Make sure original contents have document type.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(HasDocType(doc));
@@ -266,7 +248,7 @@
 
   void SerializeHTMLDOMWithoutDocTypeOnRenderer(const GURL& file_url) {
     // Make sure original contents do not have document type.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(!HasDocType(doc));
@@ -312,7 +294,7 @@
   void SerializeHTMLDOMWithNoMetaCharsetInOriginalDocOnRenderer(
       const GURL& file_url) {
     // Make sure there is no META charset declaration in original document.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
@@ -362,7 +344,7 @@
       const GURL& file_url) {
     // Make sure there are multiple META charset declarations in original
     // document.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
@@ -426,7 +408,7 @@
     LoadContents(original_contents, file_url, WebString());
 
     // Get BODY's text content in DOM.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
@@ -478,7 +460,7 @@
     // Load the test contents.
     LoadContents(original_contents, file_url, WebString());
     // Get value of BODY's title attribute in DOM.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
@@ -512,7 +494,7 @@
 
   void SerializeHTMLDOMWithNonStandardEntitiesOnRenderer(const GURL& file_url) {
     // Get value of BODY's title attribute in DOM.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
     WebElement body_element = doc.body();
@@ -544,7 +526,7 @@
     // Since for this test, we assume there is no savable sub-resource links for
     // this test file, also all links are relative URLs in this test file, so we
     // need to check those relative URLs and make sure document has BASE tag.
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     ASSERT_TRUE(doc.isHTMLDocument());
@@ -678,7 +660,7 @@
 
   void SubResourceForElementsInNonHTMLNamespaceOnRenderer(
       const GURL& file_url) {
-    WebFrame* web_frame = FindSubFrameByURL(GetWebView(), file_url);
+    WebFrame* web_frame = FindSubFrameByURL(file_url);
     ASSERT_TRUE(web_frame != NULL);
     WebDocument doc = web_frame->document();
     WebNode lastNodeInBody = doc.body().lastChild();
diff --git a/ios/provider/ios_provider_web.gyp b/ios/provider/ios_provider_web.gyp
index 90b768761..8d4a10fe 100644
--- a/ios/provider/ios_provider_web.gyp
+++ b/ios/provider/ios_provider_web.gyp
@@ -7,6 +7,7 @@
    },
   'targets': [
     {
+      # GN version: //ios/public/provider/web
       'target_name': 'ios_provider_web',
       'type': 'static_library',
       'include_dirs': [
diff --git a/ios/public/provider/web/BUILD.gn b/ios/public/provider/web/BUILD.gn
new file mode 100644
index 0000000..2df8a62c
--- /dev/null
+++ b/ios/public/provider/web/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("web") {
+  sources = [
+    "web_controller_provider.h",
+    "web_controller_provider.mm",
+    "web_ui_ios.h",
+    "web_ui_ios_controller.cc",
+    "web_ui_ios_controller.h",
+    "web_ui_ios_controller_factory.h",
+    "web_ui_ios_message_handler.cc",
+    "web_ui_ios_message_handler.h",
+  ]
+
+  deps = [
+    "//base",
+    "//ios/web",
+  ]
+}
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 1e2589f5..f191317 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -658,7 +658,7 @@
     "test/data/",
   ]
 
-  # TODO(wolenetz): Fix size_t to int truncation in win64.
+  # TODO(wolenetz): Fix size_t to int trunctaion in win64.
   # See http://crbug.com/171009
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
@@ -695,12 +695,6 @@
     ]
   }
 
-  # If ExternalClearKey is built, we can test CdmAdapter.
-  if (enable_pepper_cdms) {
-    sources += [ "cdm/cdm_adapter_unittest.cc" ]
-    deps += [ "//media/cdm/ppapi:clearkeycdm" ]
-  }
-
   if (media_use_ffmpeg) {
     sources += [
       "ffmpeg/ffmpeg_common_unittest.cc",
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 1c3f367..8eaa058 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -309,8 +309,8 @@
   promise->resolve(session_id);
 
   // No URL needed for license requests.
-  GURL empty_gurl;
-  session_message_cb_.Run(session_id, LICENSE_REQUEST, message, empty_gurl);
+  session_message_cb_.Run(session_id, LICENSE_REQUEST, message,
+                          GURL::EmptyGURL());
 }
 
 void AesDecryptor::LoadSession(SessionType session_type,
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
deleted file mode 100644
index 1b3f12b..0000000
--- a/media/cdm/cdm_adapter_unittest.cc
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/scoped_native_library.h"
-#include "media/base/cdm_callback_promise.h"
-#include "media/base/cdm_key_information.h"
-#include "media/base/media_keys.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "media/cdm/cdm_adapter.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::SaveArg;
-MATCHER(IsNotEmpty, "") {
-  return !arg.empty();
-}
-
-// TODO(jrummell): These tests are a subset of those in aes_decryptor_unittest.
-// Refactor aes_decryptor_unittest.cc to handle AesDecryptor directly and
-// via CdmAdapter once CdmAdapter supports decrypting functionality. There
-// will also be tests that only CdmAdapter supports, like file IO, which
-// will need to be handled separately.
-
-namespace media {
-
-// INITIALIZE_CDM_MODULE is a macro in api/content_decryption_module.h.
-// However, we need to pass it as a string to GetFunctionPointer() once it
-// is expanded.
-#define STRINGIFY(X) #X
-#define MAKE_STRING(X) STRINGIFY(X)
-
-const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
-
-// File name of the External ClearKey CDM on different platforms.
-const base::FilePath::CharType kExternalClearKeyCdmFileName[] =
-#if defined(OS_MACOSX)
-    FILE_PATH_LITERAL("libclearkeycdm.dylib");
-#elif defined(OS_WIN)
-    FILE_PATH_LITERAL("clearkeycdm.dll");
-#else  // OS_LINUX, etc.
-    FILE_PATH_LITERAL("libclearkeycdm.so");
-#endif
-
-// Random key ID used to create a session.
-const uint8 kKeyId[] = {
-    // base64 equivalent is AQIDBAUGBwgJCgsMDQ4PEA
-    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-};
-
-const char kKeyIdAsJWK[] = "{\"kids\": [\"AQIDBAUGBwgJCgsMDQ4PEA\"]}";
-
-const uint8 kKeyIdAsPssh[] = {
-    0x00, 0x00, 0x00, 0x00, 'p',  's',  's',  'h',   // size = 0
-    0x01,                                            // version = 1
-    0x00, 0x00, 0x00,                                // flags
-    0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,  // Common SystemID
-    0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
-    0x00, 0x00, 0x00, 0x01,                          // key count
-    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  // key
-    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-    0x00, 0x00, 0x00, 0x00,  // datasize
-};
-
-// Key is 0x0405060708090a0b0c0d0e0f10111213,
-// base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
-const char kKeyAsJWK[] =
-    "{"
-    "  \"keys\": ["
-    "    {"
-    "      \"kty\": \"oct\","
-    "      \"alg\": \"A128KW\","
-    "      \"kid\": \"AQIDBAUGBwgJCgsMDQ4PEA\","
-    "      \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
-    "    }"
-    "  ],"
-    "  \"type\": \"temporary\""
-    "}";
-
-class CdmAdapterTest : public testing::Test {
- public:
-  enum ExpectedResult { SUCCESS, FAILURE };
-
-  CdmAdapterTest() {}
-  ~CdmAdapterTest() override {}
-
- protected:
-  // Initializes the adapter. |expected_result| tests that the call succeeds
-  // or generates an error.
-  void InitializeAndExpect(base::FilePath library_path,
-                           ExpectedResult expected_result) {
-    CdmConfig cdm_config;  // default settings of false are sufficient.
-
-    CdmAdapter::Create(
-        kExternalClearKeyKeySystem, library_path, cdm_config,
-        base::Bind(&CdmAdapterTest::OnSessionMessage, base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnSessionClosed, base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnLegacySessionError,
-                   base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnSessionKeysChange,
-                   base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnSessionExpirationUpdate,
-                   base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnCdmCreated, base::Unretained(this),
-                   expected_result));
-    RunUntilIdle();
-  }
-
-  // Creates a new session using |key_id|. |session_id_| will be set
-  // when the promise is resolved. |expected_result| tests that
-  // CreateSessionAndGenerateRequest() succeeds or generates an error.
-  void CreateSessionAndExpect(EmeInitDataType data_type,
-                              const std::vector<uint8>& key_id,
-                              ExpectedResult expected_result) {
-    DCHECK(!key_id.empty());
-
-    if (expected_result == SUCCESS) {
-      EXPECT_CALL(*this,
-                  OnSessionMessage(IsNotEmpty(), _, _, GURL::EmptyGURL()));
-    }
-
-    adapter_->CreateSessionAndGenerateRequest(
-        MediaKeys::TEMPORARY_SESSION, data_type, key_id,
-        CreateSessionPromise(expected_result));
-    RunUntilIdle();
-  }
-
-  // Loads the session specified by |session_id|. |expected_result| tests
-  // that LoadSession() succeeds or generates an error.
-  void LoadSessionAndExpect(const std::string& session_id,
-                            ExpectedResult expected_result) {
-    DCHECK(!session_id.empty());
-    ASSERT_EQ(expected_result, FAILURE) << "LoadSession not supported.";
-
-    adapter_->LoadSession(MediaKeys::TEMPORARY_SESSION, session_id,
-                          CreateSessionPromise(expected_result));
-    RunUntilIdle();
-  }
-
-  // Updates the session specified by |session_id| with |key|. |expected_result|
-  // tests that the update succeeds or generates an error. |new_key_expected|
-  // is the expected parameter when the SessionKeysChange event happens.
-  void UpdateSessionAndExpect(std::string session_id,
-                              const std::string& key,
-                              ExpectedResult expected_result,
-                              bool new_key_expected) {
-    DCHECK(!key.empty());
-
-    if (expected_result == SUCCESS) {
-      EXPECT_CALL(*this,
-                  OnSessionKeysChangeCalled(session_id, new_key_expected));
-    } else {
-      EXPECT_CALL(*this, OnSessionKeysChangeCalled(_, _)).Times(0);
-    }
-
-    adapter_->UpdateSession(session_id,
-                            std::vector<uint8>(key.begin(), key.end()),
-                            CreatePromise(expected_result));
-    RunUntilIdle();
-  }
-
-  base::FilePath ExternalClearKeyLibrary() { return library_path_; }
-
-  std::string SessionId() { return session_id_; }
-
- private:
-  void SetUp() override {
-    // Determine the location of the CDM. It is expected to be in the same
-    // directory as the current module.
-    base::FilePath current_module_dir;
-    ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &current_module_dir));
-    library_path_ =
-        current_module_dir.Append(base::FilePath(kExternalClearKeyCdmFileName));
-    ASSERT_TRUE(base::PathExists(library_path_)) << library_path_.value();
-
-    // Now load the CDM library.
-    base::NativeLibraryLoadError error;
-    library_.Reset(base::LoadNativeLibrary(library_path_, &error));
-    ASSERT_TRUE(library_.is_valid()) << error.ToString();
-
-    // Call INITIALIZE_CDM_MODULE()
-    typedef void (*InitializeCdmFunc)();
-    InitializeCdmFunc initialize_cdm_func = reinterpret_cast<InitializeCdmFunc>(
-        library_.GetFunctionPointer(MAKE_STRING(INITIALIZE_CDM_MODULE)));
-    ASSERT_TRUE(initialize_cdm_func) << "No INITIALIZE_CDM_MODULE in library";
-    initialize_cdm_func();
-  }
-
-  void TearDown() override {
-    // Call DeinitializeCdmModule()
-    typedef void (*DeinitializeCdmFunc)();
-    DeinitializeCdmFunc deinitialize_cdm_func =
-        reinterpret_cast<DeinitializeCdmFunc>(
-            library_.GetFunctionPointer("DeinitializeCdmModule"));
-    ASSERT_TRUE(deinitialize_cdm_func)
-        << "No DeinitializeCdmModule() in library";
-    deinitialize_cdm_func();
-  }
-
-  void OnCdmCreated(ExpectedResult expected_result,
-                    const scoped_refptr<MediaKeys>& cdm,
-                    const std::string& error_message) {
-    if (cdm) {
-      EXPECT_EQ(expected_result, SUCCESS) << "CDM should not have loaded.";
-      adapter_ = cdm;
-    } else {
-      EXPECT_EQ(expected_result, FAILURE) << error_message;
-    }
-  }
-
-  // Create a promise. |expected_result| is used to indicate how the promise
-  // should be fulfilled.
-  scoped_ptr<SimpleCdmPromise> CreatePromise(ExpectedResult expected_result) {
-    if (expected_result == SUCCESS) {
-      EXPECT_CALL(*this, OnResolve());
-    } else {
-      EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
-    }
-
-    scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
-        base::Bind(&CdmAdapterTest::OnResolve, base::Unretained(this)),
-        base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
-    return promise.Pass();
-  }
-
-  // Create a promise to be used when a new session is created.
-  // |expected_result| is used to indicate how the promise should be fulfilled.
-  scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
-      ExpectedResult expected_result) {
-    if (expected_result == SUCCESS) {
-      EXPECT_CALL(*this, OnResolveWithSession(_))
-          .WillOnce(SaveArg<0>(&session_id_));
-    } else {
-      EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
-    }
-
-    scoped_ptr<NewSessionCdmPromise> promise(
-        new CdmCallbackPromise<std::string>(
-            base::Bind(&CdmAdapterTest::OnResolveWithSession,
-                       base::Unretained(this)),
-            base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
-    return promise.Pass();
-  }
-
-  void RunUntilIdle() { message_loop_.RunUntilIdle(); }
-
-  // Methods used for promise resolved/rejected.
-  MOCK_METHOD0(OnResolve, void());
-  MOCK_METHOD1(OnResolveWithSession, void(const std::string& session_id));
-  MOCK_METHOD3(OnReject,
-               void(MediaKeys::Exception exception_code,
-                    uint32 system_code,
-                    const std::string& error_message));
-
-  // Methods used for the events possibly generated by CdmAdapater.
-  MOCK_METHOD4(OnSessionMessage,
-               void(const std::string& session_id,
-                    MediaKeys::MessageType message_type,
-                    const std::vector<uint8_t>& message,
-                    const GURL& legacy_destination_url));
-  MOCK_METHOD1(OnSessionClosed, void(const std::string& session_id));
-  MOCK_METHOD4(OnLegacySessionError,
-               void(const std::string& session_id,
-                    MediaKeys::Exception exception,
-                    uint32_t system_code,
-                    const std::string& error_message));
-  MOCK_METHOD2(OnSessionKeysChangeCalled,
-               void(const std::string& session_id,
-                    bool has_additional_usable_key));
-  void OnSessionKeysChange(const std::string& session_id,
-                           bool has_additional_usable_key,
-                           CdmKeysInfo keys_info) {
-    // MOCK methods don't like CdmKeysInfo.
-    OnSessionKeysChangeCalled(session_id, has_additional_usable_key);
-  }
-  MOCK_METHOD2(OnSessionExpirationUpdate,
-               void(const std::string& session_id,
-                    const base::Time& new_expiry_time));
-
-  // Keep a reference to the CDM.
-  base::FilePath library_path_;
-  base::ScopedNativeLibrary library_;
-
-  scoped_refptr<MediaKeys> adapter_;
-
-  // |session_id_| is the latest result of calling CreateSession().
-  std::string session_id_;
-
-  base::MessageLoop message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(CdmAdapterTest);
-};
-
-TEST_F(CdmAdapterTest, Initialize) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-}
-
-TEST_F(CdmAdapterTest, BadLibraryPath) {
-  InitializeAndExpect(base::FilePath(FILE_PATH_LITERAL("no_library_here")),
-                      FAILURE);
-}
-
-TEST_F(CdmAdapterTest, CreateWebmSession) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
-  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
-}
-
-TEST_F(CdmAdapterTest, CreateKeyIdsSession) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  // Don't include the trailing /0 from the string in the data passed in.
-  std::vector<uint8> key_id(kKeyIdAsJWK,
-                            kKeyIdAsJWK + arraysize(kKeyIdAsJWK) - 1);
-  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, SUCCESS);
-}
-
-TEST_F(CdmAdapterTest, CreateCencSession) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  std::vector<uint8> key_id(kKeyIdAsPssh,
-                            kKeyIdAsPssh + arraysize(kKeyIdAsPssh));
-#if defined(USE_PROPRIETARY_CODECS)
-  CreateSessionAndExpect(EmeInitDataType::CENC, key_id, SUCCESS);
-#else
-  CreateSessionAndExpect(EmeInitDataType::CENC, key_id, FAILURE);
-#endif
-}
-
-TEST_F(CdmAdapterTest, CreateSessionWithBadData) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  // Use |kKeyId| but specify KEYIDS format.
-  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
-  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
-}
-
-TEST_F(CdmAdapterTest, LoadSession) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  // LoadSession() is not supported by AesDecryptor.
-  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
-  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
-}
-
-TEST_F(CdmAdapterTest, UpdateSession) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
-  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
-
-  UpdateSessionAndExpect(SessionId(), kKeyAsJWK, SUCCESS, true);
-}
-
-TEST_F(CdmAdapterTest, UpdateSessionWithBadData) {
-  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
-
-  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
-  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
-
-  UpdateSessionAndExpect(SessionId(), "random data", FAILURE, true);
-}
-
-}  // namespace media
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 61f0820..f6c7781 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -212,15 +212,23 @@
   }
 }
 
+template<typename Type>
+class ScopedResetter {
+ public:
+  explicit ScopedResetter(Type* object) : object_(object) {}
+  ~ScopedResetter() { object_->Reset(); }
+
+ private:
+  Type* const object_;
+};
+
 void INITIALIZE_CDM_MODULE() {
-  DVLOG(1) << __FUNCTION__;
 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
   av_register_all();
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 }
 
 void DeinitializeCdmModule() {
-  DVLOG(1) << __FUNCTION__;
 }
 
 void* CreateCdmInstance(int cdm_interface_version,
@@ -247,8 +255,7 @@
     return NULL;
 
   // TODO(jrummell): Obtain the proper origin for this instance.
-  GURL empty_gurl;
-  return new media::ClearKeyCdm(host, key_system_string, empty_gurl);
+  return new media::ClearKeyCdm(host, key_system_string, GURL::EmptyGURL());
 }
 
 const char* GetCdmVersion() {
diff --git a/media/media.gyp b/media/media.gyp
index b56a23b..26760c5d 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1389,15 +1389,6 @@
             'filters/decrypting_video_decoder_unittest.cc',
           ],
         }],
-        # If ExternalClearKey is built, we can test CdmAdapter.
-        ['enable_pepper_cdms == 1', {
-          'dependencies': [
-            'clearkeycdm',
-          ],
-          'sources': [
-            'cdm/cdm_adapter_unittest.cc',
-          ],
-        }],
         ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
           'sources': [
             'filters/h264_bitstream_buffer_unittest.cc',
diff --git a/net/dns/dns_session.cc b/net/dns/dns_session.cc
index 4d8f61e..9ea2db9 100644
--- a/net/dns/dns_session.cc
+++ b/net/dns/dns_session.cc
@@ -93,8 +93,8 @@
   UMA_HISTOGRAM_CUSTOM_COUNTS(
       "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11);
   for (size_t i = 0; i < config_.nameservers.size(); ++i) {
-    server_stats_.push_back(new ServerStats(config_.timeout,
-                                            rtt_buckets_.Pointer()));
+    server_stats_.push_back(make_scoped_ptr(
+        new ServerStats(config_.timeout, rtt_buckets_.Pointer())));
   }
 }
 
diff --git a/net/dns/dns_session.h b/net/dns/dns_session.h
index e878a57..48af67fb 100644
--- a/net/dns/dns_session.h
+++ b/net/dns/dns_session.h
@@ -10,7 +10,6 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/metrics/bucket_ranges.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
@@ -131,7 +130,7 @@
   struct ServerStats;
 
   // Track runtime statistics of each DNS server.
-  ScopedVector<ServerStats> server_stats_;
+  std::vector<scoped_ptr<ServerStats>> server_stats_;
 
   // Buckets shared for all |ServerStats::rtt_histogram|.
   struct RttBuckets : public base::BucketRanges {
diff --git a/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.cpp b/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.cpp
index 72fe57dc..9654ddf 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.cpp
@@ -80,9 +80,14 @@
     return canAccessFrame(isolate, accessingWindow, target->securityContext()->securityOrigin(), target->domWindow(), exceptionState);
 }
 
+bool BindingSecurity::shouldAllowAccessToNode(v8::Isolate* isolate, LocalDOMWindow* accessingWindow, Node* target, SecurityReportingOption reportingOption)
+{
+    return target && canAccessFrame(isolate, accessingWindow, target->document().securityOrigin(), target->document().domWindow(), reportingOption);
+}
+
 bool BindingSecurity::shouldAllowAccessToNode(v8::Isolate* isolate, LocalDOMWindow* accessingWindow, Node* target, ExceptionState& exceptionState)
 {
     return target && canAccessFrame(isolate, accessingWindow, target->document().securityOrigin(), target->document().domWindow(), exceptionState);
 }
 
-}
+} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.h b/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.h
index 9fed5178..f8fbe35 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.h
+++ b/third_party/WebKit/Source/bindings/core/v8/BindingSecurity.h
@@ -51,7 +51,11 @@
 class BindingSecurity {
     STATIC_ONLY(BindingSecurity);
 public:
+    // Check the access to the return value.
+    static bool shouldAllowAccessToNode(v8::Isolate*, LocalDOMWindow* accessingWindow, Node*, SecurityReportingOption);
     static bool shouldAllowAccessToNode(v8::Isolate*, LocalDOMWindow* accessingWindow, Node*, ExceptionState&);
+
+    // Check the access to the receiver.
     CORE_EXPORT static bool shouldAllowAccessToFrame(v8::Isolate*, LocalDOMWindow* accessingWindow, Frame*, SecurityReportingOption = ReportSecurityError);
     CORE_EXPORT static bool shouldAllowAccessToFrame(v8::Isolate*, LocalDOMWindow* accessingWindow, Frame*, ExceptionState&);
 };
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp
index d5a3f9a..b53b987 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp
@@ -108,12 +108,7 @@
 {
     LocalDOMWindow* impl = toLocalDOMWindow(V8Window::toImpl(info.Holder()));
 
-    // Do the security check against the parent frame rather than
-    // frameElement() itself, so that a remote parent frame can be handled
-    // properly. In that case, there's no frameElement(), yet we should still
-    // return null and deny access.
-    Frame* target = impl->frame() ? impl->frame()->tree().parent() : nullptr;
-    if (!BindingSecurity::shouldAllowAccessToFrame(info.GetIsolate(), callingDOMWindow(info.GetIsolate()), target, DoNotReportSecurityError)) {
+    if (!BindingSecurity::shouldAllowAccessToNode(info.GetIsolate(), callingDOMWindow(info.GetIsolate()), impl->frameElement(), DoNotReportSecurityError)) {
         v8SetReturnValueNull(info);
         return;
     }
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 65b8ef84..f5b3344 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -724,10 +724,9 @@
 
 Element* LocalDOMWindow::frameElement() const
 {
-    if (!frame())
+    if (!(frame() && frame()->owner() && frame()->owner()->isLocal()))
         return nullptr;
 
-    // The bindings security check should ensure we're same origin...
     return toHTMLFrameOwnerElement(frame()->owner());
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp
index c85256a..f0f31f0 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -85,7 +85,7 @@
 String HTMLElement::nodeName() const
 {
     // localNameUpper may intern and cache an AtomicString.
-    RELEASE_ASSERT(isMainThread());
+    ASSERT(isMainThread());
 
     // FIXME: Would be nice to have an atomicstring lookup based off uppercase
     // chars that does not have to copy the string on a hit in the hash.
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 817c18f..845e3ed 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -782,7 +782,6 @@
     // Manual selection anchor is reset when manipulating the select programmatically.
     m_activeSelectionAnchorIndex = -1;
     setOptionsChangedOnLayoutObject();
-    setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::ControlValue));
     if (!inDocument()) {
         if (HTMLOptionsCollection* collection = cachedCollection<HTMLOptionsCollection>(SelectOptions))
             collection->invalidateCache();
diff --git a/third_party/WebKit/Source/core/inspector/InspectedFrames.h b/third_party/WebKit/Source/core/inspector/InspectedFrames.h
index 00aa5b00..b7682404 100644
--- a/third_party/WebKit/Source/core/inspector/InspectedFrames.h
+++ b/third_party/WebKit/Source/core/inspector/InspectedFrames.h
@@ -6,6 +6,7 @@
 #define InspectedFrames_h
 
 #include "core/CoreExport.h"
+#include "platform/heap/Handle.h"
 #include "wtf/Forward.h"
 #include "wtf/Noncopyable.h"
 
@@ -13,10 +14,12 @@
 
 class LocalFrame;
 
-class CORE_EXPORT InspectedFrames {
+class CORE_EXPORT InspectedFrames final : public NoBaseWillBeGarbageCollectedFinalized<InspectedFrames> {
     WTF_MAKE_NONCOPYABLE(InspectedFrames);
+    USING_FAST_MALLOC_WILL_BE_REMOVED(InspectedFrames);
 public:
     class CORE_EXPORT Iterator {
+        STACK_ALLOCATED();
     public:
         Iterator operator++(int);
         Iterator& operator++();
@@ -27,19 +30,30 @@
     private:
         friend class InspectedFrames;
         Iterator(LocalFrame* root, LocalFrame* current);
-        LocalFrame* m_root;
-        LocalFrame* m_current;
+        RawPtrWillBeMember<LocalFrame> m_root;
+        RawPtrWillBeMember<LocalFrame> m_current;
     };
 
-    explicit InspectedFrames(LocalFrame* root);
+    static PassOwnPtrWillBeRawPtr<InspectedFrames> create(LocalFrame* root)
+    {
+        return adoptPtrWillBeNoop(new InspectedFrames(root));
+    }
+
     LocalFrame* root() { return m_root; }
     bool contains(LocalFrame*) const;
     LocalFrame* frameWithSecurityOrigin(const String& originRawString);
     Iterator begin();
     Iterator end();
 
+    DEFINE_INLINE_TRACE()
+    {
+        visitor->trace(m_root);
+    }
+
 private:
-    LocalFrame* m_root;
+    explicit InspectedFrames(LocalFrame*);
+
+    RawPtrWillBeMember<LocalFrame> m_root;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
index 62ff7b5..4df7ecd 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -469,6 +469,7 @@
 DEFINE_TRACE(InspectorAnimationAgent)
 {
 #if ENABLE(OILPAN)
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_domAgent);
     visitor->trace(m_cssAgent);
     visitor->trace(m_injectedScriptManager);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.h b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.h
index 225b326..ace5214 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.h
@@ -71,7 +71,7 @@
     Animation* animationClone(Animation*);
     String createCSSId(Animation&);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
     RawPtrWillBeMember<InspectorCSSAgent> m_cssAgent;
     RawPtrWillBeMember<InjectedScriptManager> m_injectedScriptManager;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.cpp
index 8e336691..2278185c 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.cpp
@@ -201,8 +201,8 @@
 
 DEFINE_TRACE(InspectorApplicationCacheAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
 } // namespace blink
-
diff --git a/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.h b/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.h
index 2d47b59..edc1fdb 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorApplicationCacheAgent.h
@@ -66,14 +66,15 @@
     void getApplicationCacheForFrame(ErrorString*, const String& frameId, RefPtr<TypeBuilder::ApplicationCache::ApplicationCache>&) override;
 
 private:
-    InspectorApplicationCacheAgent(InspectedFrames*);
+    explicit InspectorApplicationCacheAgent(InspectedFrames*);
+
     PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCache> buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList&, const ApplicationCacheHost::CacheInfo&);
     PassRefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::ApplicationCacheResource> > buildArrayForApplicationCacheResources(const ApplicationCacheHost::ResourceInfoList&);
     PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCacheResource> buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo&);
 
     DocumentLoader* assertFrameWithDocumentLoader(ErrorString*, String frameId);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 22564014..438214f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -1959,6 +1959,7 @@
 DEFINE_TRACE(InspectorCSSAgent)
 {
     visitor->trace(m_domAgent);
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_resourceAgent);
     visitor->trace(m_resourceContentLoader);
 #if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
index 0d9b5de..b509f91 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
@@ -210,7 +210,7 @@
     void resetPseudoStates();
 
     RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     RawPtrWillBeMember<InspectorResourceAgent> m_resourceAgent;
     RawPtrWillBeMember<InspectorResourceContentLoader> m_resourceContentLoader;
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index 999d5671..9309d9f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -2144,6 +2144,7 @@
 DEFINE_TRACE(InspectorDOMAgent)
 {
     visitor->trace(m_domListener);
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_injectedScriptManager);
 #if ENABLE(OILPAN)
     visitor->trace(m_documentNodeToIdMap);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
index f8ff183..6dbeb79 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
@@ -245,7 +245,7 @@
 
     RawPtrWillBeMember<InspectorRevalidateDOMTask> revalidateTask();
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     RawPtrWillBeMember<InjectedScriptManager> m_injectedScriptManager;
     Client* m_client;
     RawPtrWillBeMember<DOMListener> m_domListener;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp
index 57cbb06e..38e7a6d 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp
@@ -208,8 +208,8 @@
 
 DEFINE_TRACE(InspectorInputAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
 } // namespace blink
-
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.h b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.h
index 12bb726..6422132 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.h
@@ -61,7 +61,7 @@
 private:
     explicit InspectorInputAgent(InspectedFrames*);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
 };
 
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
index 8da31e8..9f9497d 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -159,6 +159,7 @@
 
 DEFINE_TRACE(InspectorLayerTreeAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.h b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.h
index 016fa3f7..c960f0e 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.h
@@ -103,7 +103,7 @@
     void gatherGraphicsLayers(GraphicsLayer*, HashMap<int, int>& layerIdToNodeIdMap, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >&);
     int idForNode(Node*);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     Vector<int, 2> m_pageOverlayLayerIds;
 
     typedef HashMap<String, RefPtr<PictureSnapshot> > SnapshotById;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index e53a831..61b9688 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -789,6 +789,7 @@
 
 DEFINE_TRACE(InspectorPageAgent)
 {
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_debuggerAgent);
     visitor->trace(m_inspectorResourceContentLoader);
     InspectorBaseAgent::trace(visitor);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
index 63917a6..a34aaeb 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
@@ -143,7 +143,7 @@
 
     PassRefPtr<TypeBuilder::Page::Frame> buildObjectForFrame(LocalFrame*);
     PassRefPtr<TypeBuilder::Page::FrameResourceTree> buildObjectForFrameTree(LocalFrame*);
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     RawPtrWillBeMember<InspectorDebuggerAgent> m_debuggerAgent;
     Client* m_client;
     long m_lastScriptIdentifier;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
index 8a4228a..3c89b41b 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.cpp
@@ -411,6 +411,7 @@
 
 DEFINE_TRACE(InspectorResourceAgent)
 {
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_resourcesData);
     visitor->trace(m_replayXHRs);
     visitor->trace(m_replayXHRsToBeDeleted);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
index eebf270..d266102 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h
@@ -165,7 +165,7 @@
 
     bool getResponseBodyBlob(const String& requestId, PassRefPtrWillBeRawPtr<GetResponseBodyCallback>);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     String m_userAgentOverride;
     String m_hostId;
     OwnPtrWillBeMember<NetworkResourcesData> m_resourcesData;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
index 5ce3fd9a..0a30818 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
@@ -93,7 +93,8 @@
 {
     m_started = true;
     WillBeHeapVector<RawPtrWillBeMember<Document>> documents;
-    for (LocalFrame* frame : InspectedFrames(m_inspectedFrame)) {
+    OwnPtrWillBeRawPtr<InspectedFrames> inspectedFrames = InspectedFrames::create(m_inspectedFrame);
+    for (LocalFrame* frame : *inspectedFrames) {
         documents.append(frame->document());
         documents.appendVector(InspectorPageAgent::importsForFrame(frame));
     }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.cpp
index 219b5d0..cab7508 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.cpp
@@ -38,6 +38,7 @@
 DEFINE_TRACE(InspectorTracingAgent)
 {
     visitor->trace(m_workerAgent);
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.h b/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.h
index ad6cf17..522f039 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorTracingAgent.h
@@ -59,7 +59,7 @@
     int m_layerTreeId;
     Client* m_client;
     RawPtrWillBeMember<InspectorWorkerAgent> m_workerAgent;
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/PageConsoleAgent.cpp b/third_party/WebKit/Source/core/inspector/PageConsoleAgent.cpp
index 63e8a43..227b3e2 100644
--- a/third_party/WebKit/Source/core/inspector/PageConsoleAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/PageConsoleAgent.cpp
@@ -63,6 +63,7 @@
 DEFINE_TRACE(PageConsoleAgent)
 {
     visitor->trace(m_inspectorDOMAgent);
+    visitor->trace(m_inspectedFrames);
     InspectorConsoleAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/PageConsoleAgent.h b/third_party/WebKit/Source/core/inspector/PageConsoleAgent.h
index 8a689e5d..279c35c 100644
--- a/third_party/WebKit/Source/core/inspector/PageConsoleAgent.h
+++ b/third_party/WebKit/Source/core/inspector/PageConsoleAgent.h
@@ -72,7 +72,7 @@
     void clearMessages(ErrorString*) override;
 
     RawPtrWillBeMember<InspectorDOMAgent> m_inspectorDOMAgent;
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     HashSet<WorkerGlobalScopeProxy*> m_workersWithEnabledConsole;
 
     static int s_enabledAgentCount;
diff --git a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp
index 0480a3a..6cb0c23 100644
--- a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp
@@ -70,6 +70,7 @@
 
 DEFINE_TRACE(PageDebuggerAgent)
 {
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_injectedScriptManager);
     InspectorDebuggerAgent::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h
index bf798d59..f0bbd41 100644
--- a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h
+++ b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h
@@ -70,7 +70,7 @@
     // V8DebuggerAgent::Client implemntation.
     bool canExecuteScripts() const;
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     RawPtrWillBeMember<InjectedScriptManager> m_injectedScriptManager;
     HashMap<String, String> m_compiledScriptURLs;
 };
diff --git a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp
index d456478..4e8e789 100644
--- a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp
@@ -62,6 +62,7 @@
 
 DEFINE_TRACE(PageRuntimeAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorRuntimeAgent::trace(visitor);
 }
 
@@ -175,4 +176,3 @@
 }
 
 } // namespace blink
-
diff --git a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h
index e6815d2..4584ef0 100644
--- a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h
+++ b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h
@@ -66,7 +66,7 @@
     void reportExecutionContextCreation();
     void reportExecutionContext(ScriptState*, bool isPageContext, const String& origin, const String& frameId);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     bool m_mainWorldContextCreated;
     typedef HashMap<RefPtr<ScriptState>, int> ScriptStateToId;
     ScriptStateToId m_scriptStateToId;
diff --git a/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.cpp b/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.cpp
index 63c79d4..9db56ac 100644
--- a/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.cpp
+++ b/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.cpp
@@ -765,6 +765,7 @@
 
 DEFINE_TRACE(InspectorFileSystemAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.h b/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.h
index 3a2ee25..fab4370 100644
--- a/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.h
+++ b/third_party/WebKit/Source/modules/filesystem/InspectorFileSystemAgent.h
@@ -65,7 +65,7 @@
     bool assertEnabled(ErrorString*);
     ExecutionContext* assertExecutionContextForOrigin(ErrorString*, SecurityOrigin*);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
     bool m_enabled;
 };
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
index 487d7d1e4..b827876 100644
--- a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
@@ -831,6 +831,7 @@
 
 DEFINE_TRACE(InspectorIndexedDBAgent)
 {
+    visitor->trace(m_inspectedFrames);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.h b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.h
index a86fc86..0cc331f 100644
--- a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.h
+++ b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.h
@@ -63,7 +63,7 @@
 private:
     explicit InspectorIndexedDBAgent(InspectedFrames*);
 
-    InspectedFrames* m_inspectedFrames;
+    RawPtrWillBeMember<InspectedFrames> m_inspectedFrames;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/storage/InspectorDOMStorageAgent.cpp b/third_party/WebKit/Source/modules/storage/InspectorDOMStorageAgent.cpp
index 4c0eb81..8da4193cb 100644
--- a/third_party/WebKit/Source/modules/storage/InspectorDOMStorageAgent.cpp
+++ b/third_party/WebKit/Source/modules/storage/InspectorDOMStorageAgent.cpp
@@ -210,7 +210,8 @@
     if (!m_page->mainFrame()->isLocalFrame())
         return nullptr;
 
-    LocalFrame* frame = InspectedFrames(m_page->deprecatedLocalMainFrame()).frameWithSecurityOrigin(securityOrigin);
+    OwnPtrWillBeRawPtr<InspectedFrames> inspectedFrames = InspectedFrames::create(m_page->deprecatedLocalMainFrame());
+    LocalFrame* frame = inspectedFrames->frameWithSecurityOrigin(securityOrigin);
     if (!frame) {
         if (errorString)
             *errorString = "LocalFrame not found for the given security origin";
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 62258a2b..e21c2677 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -320,7 +320,7 @@
     , m_resourceContentLoader(InspectorResourceContentLoader::create(m_webLocalFrameImpl->frame()))
     , m_state(adoptPtrWillBeNoop(new InspectorCompositeState(this)))
     , m_overlay(overlay)
-    , m_inspectedFrames(adoptPtr(new InspectedFrames(m_webLocalFrameImpl->frame())))
+    , m_inspectedFrames(InspectedFrames::create(m_webLocalFrameImpl->frame()))
     , m_inspectorAgent(nullptr)
     , m_domAgent(nullptr)
     , m_pageAgent(nullptr)
@@ -413,6 +413,7 @@
     visitor->trace(m_resourceContentLoader);
     visitor->trace(m_state);
     visitor->trace(m_overlay);
+    visitor->trace(m_inspectedFrames);
     visitor->trace(m_inspectorAgent);
     visitor->trace(m_domAgent);
     visitor->trace(m_pageAgent);
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
index 9ce980bb..f377d56 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
@@ -143,7 +143,7 @@
     OwnPtrWillBeMember<InspectorResourceContentLoader> m_resourceContentLoader;
     OwnPtrWillBeMember<InspectorCompositeState> m_state;
     OwnPtrWillBeMember<InspectorOverlay> m_overlay;
-    OwnPtr<InspectedFrames> m_inspectedFrames;
+    OwnPtrWillBeMember<InspectedFrames> m_inspectedFrames;
 
     RawPtrWillBeMember<InspectorInspectorAgent> m_inspectorAgent;
     RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index c861a10e..0a1419e 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -108,6 +108,8 @@
   // Register events.
   ui.listContainer.element.addEventListener(
       'keydown', this.onListKeyDown_.bind(this));
+  ui.directoryTree.addEventListener(
+      'keydown', this.onDirectoryTreeKeyDown_.bind(this));
   ui.listContainer.element.addEventListener(
       ListContainer.EventType.TEXT_SEARCH, this.onTextSearch_.bind(this));
   ui.listContainer.table.list.addEventListener(
@@ -270,6 +272,28 @@
 };
 
 /**
+ * KeyDown event handler for the directory tree element.
+ * @param {Event} event Key event.
+ * @private
+ */
+MainWindowComponent.prototype.onDirectoryTreeKeyDown_ = function(event) {
+  // Enter => Change directory or perform default action.
+  if (util.getKeyModifiers(event) + event.keyIdentifier === 'Enter') {
+    var selectedItem = this.ui_.directoryTree.selectedItem;
+    if (!selectedItem)
+      return;
+    selectedItem.activate();
+    if (this.dialogType_ !== DialogType.FULL_PAGE &&
+        !selectedItem.hasAttribute('renaming') &&
+        util.isSameEntry(
+            this.directoryModel_.getCurrentDirEntry(), selectedItem.entry) &&
+        !this.ui_.dialogFooter.okButton.disabled) {
+      this.ui_.dialogFooter.okButton.click();
+    }
+  }
+};
+
+/**
  * KeyDown event handler for the div#list-container element.
  * @param {Event} event Key event.
  * @private
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index e4d2778..9b974c2 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -1275,19 +1275,6 @@
 };
 
 /**
-  * Handles keydown events on the tree and activates the selected item on Enter.
-  * @param {Event} e The click event object.
-  * @override
-  */
-DirectoryTree.prototype.handleKeyDown = function(e) {
-  cr.ui.Tree.prototype.handleKeyDown.call(this, e);
-  if (util.getKeyModifiers(e) === '' && e.keyIdentifier === 'Enter') {
-    if (this.selectedItem)
-      this.selectedItem.activate();
-  }
-};
-
-/**
  * Invoked when the filter is changed.
  * @private
  */