Import Cobalt 2.10363 2016-09-02
diff --git a/src/base/threading/thread.cc b/src/base/threading/thread.cc
index c940775..29b851a 100644
--- a/src/base/threading/thread.cc
+++ b/src/base/threading/thread.cc
@@ -17,21 +17,10 @@
 
 namespace base {
 
-namespace {
-
-// We use this thread-local variable to record whether or not a thread exited
-// because its Stop method was called.  This allows us to catch cases where
-// MessageLoop::Quit() is called directly, which is unexpected when using a
-// Thread to setup and run a MessageLoop.
-base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
 // This is used to trigger the message loop to exit.
-void ThreadQuitHelper() {
+void Thread::ThreadQuitHelper() {
   MessageLoop::current()->Quit();
-  Thread::SetThreadWasQuitProperly(true);
+  SetThreadWasQuitProperly(true);
 }
 
 // Used to pass data to ThreadMain.  This structure is allocated on the stack
@@ -60,7 +49,12 @@
       thread_(0),
       message_loop_(NULL),
       thread_id_(kInvalidThreadId),
-      name_(name) {
+      name_(name)
+#ifndef NDEBUG
+      ,
+      was_quit_properly_(false)
+#endif
+{
 }
 
 Thread::~Thread() {
@@ -153,7 +147,8 @@
     return;
 
   stopping_ = true;
-  message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+  message_loop_->PostTask(
+      FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, base::Unretained(this)));
 }
 
 bool Thread::IsRunning() const {
@@ -165,15 +160,17 @@
 }
 
 void Thread::SetThreadWasQuitProperly(bool flag) {
-  lazy_tls_bool.Pointer()->Set(flag);
+#ifndef NDEBUG
+  was_quit_properly_ = flag;
+#endif
 }
 
 bool Thread::GetThreadWasQuitProperly() {
-  bool quit_properly = true;
 #ifndef NDEBUG
-  quit_properly = lazy_tls_bool.Pointer()->Get();
+  return was_quit_properly_;
+#else
+  return true;
 #endif
-  return quit_properly;
 }
 
 void Thread::ThreadMain() {
diff --git a/src/base/threading/thread.h b/src/base/threading/thread.h
index d0f89af..0a99852 100644
--- a/src/base/threading/thread.h
+++ b/src/base/threading/thread.h
@@ -167,8 +167,9 @@
   // Called just after the message loop ends
   virtual void CleanUp() {}
 
-  static void SetThreadWasQuitProperly(bool flag);
-  static bool GetThreadWasQuitProperly();
+  void ThreadQuitHelper();
+  void SetThreadWasQuitProperly(bool flag);
+  bool GetThreadWasQuitProperly();
 
   void set_message_loop(MessageLoop* message_loop) {
     message_loop_ = message_loop;
@@ -218,6 +219,14 @@
   // The name of the thread.  Used for debugging purposes.
   std::string name_;
 
+#ifndef NDEBUG
+  // We use this member variable to record whether or not a thread exited
+  // because its Stop method was called.  This allows us to catch cases where
+  // MessageLoop::Quit() is called directly, which is unexpected when using a
+  // Thread to setup and run a MessageLoop.
+  bool was_quit_properly_;
+#endif
+
   friend void ThreadQuitHelper();
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/src/cobalt/audio/audio_buffer_source_node.cc b/src/cobalt/audio/audio_buffer_source_node.cc
index 9bcc91e..6f3538f 100644
--- a/src/cobalt/audio/audio_buffer_source_node.cc
+++ b/src/cobalt/audio/audio_buffer_source_node.cc
@@ -55,15 +55,17 @@
 }
 
 // TODO: Fully implement start and stop method. The starting time is
-// based on the current time of AudioContext. We only support start at 0
-// currently.
+// based on the current time of AudioContext. We only support start at 0 and
+// stop at 0 currently.
 void AudioBufferSourceNode::Start(double when, double offset, double duration,
                                   script::ExceptionState* exception_state) {
   AudioLock::AutoLock lock(audio_lock());
 
-  DCHECK_EQ(when, 0);
-  DCHECK_EQ(offset, 0);
-  DCHECK_EQ(duration, 0);
+  if (when != 0 || offset != 0 || duration != 0) {
+    dom::DOMException::Raise(dom::DOMException::kInvalidStateErr,
+                             exception_state);
+    return;
+  }
 
   if (state_ != kNone) {
     dom::DOMException::Raise(dom::DOMException::kInvalidStateErr,
@@ -77,7 +79,11 @@
                                  script::ExceptionState* exception_state) {
   AudioLock::AutoLock lock(audio_lock());
 
-  DCHECK_EQ(when, 0);
+  if (when != 0) {
+    dom::DOMException::Raise(dom::DOMException::kInvalidStateErr,
+                             exception_state);
+    return;
+  }
 
   if (state_ != kStarted) {
     dom::DOMException::Raise(dom::DOMException::kInvalidStateErr,
diff --git a/src/cobalt/base/console_commands.cc b/src/cobalt/base/console_commands.cc
index 8780bcf..eecf31a 100644
--- a/src/cobalt/base/console_commands.cc
+++ b/src/cobalt/base/console_commands.cc
@@ -47,7 +47,7 @@
 }
 
 void ConsoleCommandManager::HandleCommand(const std::string& channel,
-                                          const std::string& message) {
+                                          const std::string& message) const {
   DCHECK_GT(channel.length(), size_t(0));
   base::AutoLock auto_lock(lock_);
   CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel);
@@ -60,6 +60,7 @@
 
 std::set<std::string> ConsoleCommandManager::GetRegisteredChannels() const {
   std::set<std::string> result;
+  base::AutoLock auto_lock(lock_);
   for (CommandHandlerMap::const_iterator iter = command_channel_map_.begin();
        iter != command_channel_map_.end(); ++iter) {
     result.insert(iter->first);
@@ -69,6 +70,7 @@
 
 std::string ConsoleCommandManager::GetShortHelp(
     const std::string& channel) const {
+  base::AutoLock auto_lock(lock_);
   CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel);
   if (iter != command_channel_map_.end()) {
     return iter->second->short_help();
@@ -78,6 +80,7 @@
 
 std::string ConsoleCommandManager::GetLongHelp(
     const std::string& channel) const {
+  base::AutoLock auto_lock(lock_);
   CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel);
   if (iter != command_channel_map_.end()) {
     return iter->second->long_help();
@@ -114,7 +117,7 @@
 ConsoleCommandManager::CommandHandler::~CommandHandler() {}
 
 void ConsoleCommandManager::HandleCommand(const std::string& channel,
-                                          const std::string& message) {
+                                          const std::string& message) const {
   UNREFERENCED_PARAMETER(channel);
   UNREFERENCED_PARAMETER(message);
 }
diff --git a/src/cobalt/base/console_commands.h b/src/cobalt/base/console_commands.h
index 6407174..47144d6 100644
--- a/src/cobalt/base/console_commands.h
+++ b/src/cobalt/base/console_commands.h
@@ -72,7 +72,8 @@
 
   // Handles a command by posting the message to the handler registered for
   // the specified channel, if any.
-  void HandleCommand(const std::string& channel, const std::string& message);
+  void HandleCommand(const std::string& channel,
+                     const std::string& message) const;
 
   // Returns a set of all the currently registered channels.
   std::set<std::string> GetRegisteredChannels() const;
@@ -96,7 +97,7 @@
   void RegisterCommandHandler(const CommandHandler* handler);
   void UnregisterCommandHandler(const CommandHandler* handler);
 
-  base::Lock lock_;
+  mutable base::Lock lock_;
 
   // Map of command handlers, one for each channel.
   CommandHandlerMap command_channel_map_;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
index 546197c..8e92cae 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
@@ -411,7 +411,10 @@
 // static
 JSObject* MozjsAnonymousIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -430,7 +433,10 @@
 //static
 const JSClass* MozjsAnonymousIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
index 9cb9a00..5b5af82 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
@@ -383,7 +383,10 @@
 // static
 JSObject* MozjsAnonymousNamedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -402,7 +405,10 @@
 //static
 const JSClass* MozjsAnonymousNamedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
index 0b1e79d..04c9194 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
@@ -502,7 +502,10 @@
 // static
 JSObject* MozjsAnonymousNamedIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -521,7 +524,10 @@
 //static
 const JSClass* MozjsAnonymousNamedIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
index 4073689..1bc5cc0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
@@ -389,7 +389,10 @@
 // static
 JSObject* MozjsArbitraryInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -408,7 +411,10 @@
 //static
 const JSClass* MozjsArbitraryInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
index f0e5922..7f786d8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
@@ -367,7 +367,10 @@
 // static
 JSObject* MozjsBaseInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -386,7 +389,10 @@
 //static
 const JSClass* MozjsBaseInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
index 86e82f3..e0895ab 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
@@ -437,7 +437,10 @@
 // static
 JSObject* MozjsBooleanTypeTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -456,7 +459,10 @@
 //static
 const JSClass* MozjsBooleanTypeTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
index 379afa8..90f8065 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
@@ -666,7 +666,10 @@
 // static
 JSObject* MozjsCallbackFunctionInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -685,7 +688,10 @@
 //static
 const JSClass* MozjsCallbackFunctionInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
index b387cf6..7f68bd2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
@@ -435,7 +435,10 @@
 // static
 JSObject* MozjsCallbackInterfaceInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -454,7 +457,10 @@
 //static
 const JSClass* MozjsCallbackInterfaceInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
index dcf4ed6..5b3a117 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
@@ -480,7 +480,10 @@
 // static
 JSObject* MozjsConditionalInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -499,7 +502,10 @@
 //static
 const JSClass* MozjsConditionalInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
index 467b6de..a874765 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
@@ -345,7 +345,10 @@
 // static
 JSObject* MozjsConstantsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -364,7 +367,10 @@
 //static
 const JSClass* MozjsConstantsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
index 8367aeb..1ce35d8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
@@ -304,7 +304,10 @@
 // static
 JSObject* MozjsConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -323,7 +326,10 @@
 //static
 const JSClass* MozjsConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
index bcf7385..fcb47c4 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
@@ -388,7 +388,10 @@
 // static
 JSObject* MozjsConstructorWithArgumentsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -407,7 +410,10 @@
 //static
 const JSClass* MozjsConstructorWithArgumentsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
index 18dd40a..9492765 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
@@ -548,7 +548,10 @@
 // static
 JSObject* MozjsDOMStringTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -567,7 +570,10 @@
 //static
 const JSClass* MozjsDOMStringTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index e84fa83..eda9b8c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -713,7 +713,10 @@
 // static
 JSObject* MozjsDerivedGetterSetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -732,7 +735,10 @@
 //static
 const JSClass* MozjsDerivedGetterSetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
index 3edab69..51928b3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
@@ -367,7 +367,10 @@
 // static
 JSObject* MozjsDerivedInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -386,7 +389,10 @@
 //static
 const JSClass* MozjsDerivedInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
index 54c8308..0e86696 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
@@ -379,7 +379,10 @@
 // static
 JSObject* MozjsDisabledInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -398,7 +401,10 @@
 //static
 const JSClass* MozjsDisabledInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
index 1ec0bac..0e08a3f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
@@ -363,7 +363,10 @@
 // static
 JSObject* MozjsEnumerationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -382,7 +385,10 @@
 //static
 const JSClass* MozjsEnumerationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
index 8a5b4b0..4a0476a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
@@ -271,16 +271,17 @@
   DCHECK(!interface_data->interface_object);
   DCHECK(JS_IsGlobalObject(global_object));
 
-  JS::RootedObject parent_prototype(
-      context, JS_GetObjectPrototype(context, global_object));
+  // Get Error prototype.
+  JS::RootedObject parent_prototype(context);
+  bool success_check = js_GetClassPrototype(
+      context, GetExceptionProtoKey(JSEXN_ERR), &parent_prototype);
+  DCHECK(success_check);
   DCHECK(parent_prototype);
 
-  JS::RootedObject prototype(context);
-  // Get Error prototype.
-  bool success_check = js_GetClassPrototype(
-      context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
-  DCHECK(success_check);
-  interface_data->prototype = prototype;
+  // Create the Prototype object.
+  interface_data->prototype = JS_NewObjectWithGivenProto(
+      context, &interface_data->prototype_class_definition, parent_prototype,
+      NULL);
   bool success = JS_DefineProperties(
       context, interface_data->prototype, prototype_properties);
   DCHECK(success);
@@ -351,7 +352,10 @@
 // static
 JSObject* MozjsExceptionObjectInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -370,7 +374,10 @@
 //static
 const JSClass* MozjsExceptionObjectInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
index c58594c..cc462b9 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
@@ -389,7 +389,10 @@
 // static
 JSObject* MozjsExceptionsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -408,7 +411,10 @@
 //static
 const JSClass* MozjsExceptionsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
index 3753f38..ea9bef6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
@@ -329,7 +329,10 @@
 // static
 JSObject* MozjsExtendedIDLAttributesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -348,7 +351,10 @@
 //static
 const JSClass* MozjsExtendedIDLAttributesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
index 1a71dae..1ac39e0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
@@ -304,7 +304,10 @@
 // static
 JSObject* MozjsGetOpaqueRootInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -323,7 +326,10 @@
 //static
 const JSClass* MozjsGetOpaqueRootInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
index e02ee9c..462c526 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
@@ -327,7 +327,10 @@
 // static
 JSObject* MozjsGlobalInterfaceParent::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -346,7 +349,10 @@
 //static
 const JSClass* MozjsGlobalInterfaceParent::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index a392376..b950039 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -606,7 +606,10 @@
 // static
 JSObject* MozjsIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -625,7 +628,10 @@
 //static
 const JSClass* MozjsIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
index d629315..3253e9d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
@@ -320,7 +320,10 @@
 // static
 JSObject* MozjsInterfaceWithUnsupportedProperties::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -339,7 +342,10 @@
 //static
 const JSClass* MozjsInterfaceWithUnsupportedProperties::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
index bdb7519..82151fb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
@@ -304,7 +304,10 @@
 // static
 JSObject* MozjsNamedConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -323,7 +326,10 @@
 //static
 const JSClass* MozjsNamedConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index f77d8de..f0e1c02 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -578,7 +578,10 @@
 // static
 JSObject* MozjsNamedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -597,7 +600,10 @@
 //static
 const JSClass* MozjsNamedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index bc60f6a..bca075c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -839,7 +839,10 @@
 // static
 JSObject* MozjsNamedIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -858,7 +861,10 @@
 //static
 const JSClass* MozjsNamedIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
index d30656e..07cf2d8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
@@ -368,7 +368,10 @@
 // static
 JSObject* MozjsNestedPutForwardsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -387,7 +390,10 @@
 //static
 const JSClass* MozjsNestedPutForwardsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
index 1848abb..5780f10 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
@@ -292,7 +292,10 @@
 // static
 JSObject* MozjsNoConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -311,7 +314,10 @@
 //static
 const JSClass* MozjsNoConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
index 1ad2cbb..fc4d206 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
@@ -252,7 +252,10 @@
 // static
 JSObject* MozjsNoInterfaceObjectInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -271,7 +274,10 @@
 //static
 const JSClass* MozjsNoInterfaceObjectInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
index 04c7ec4..5ac3c47 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
@@ -876,7 +876,10 @@
 // static
 JSObject* MozjsNullableTypesTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -895,7 +898,10 @@
 //static
 const JSClass* MozjsNullableTypesTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
index 546ed1a..4c45a29 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
@@ -1742,7 +1742,10 @@
 // static
 JSObject* MozjsNumericTypesTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -1761,7 +1764,10 @@
 //static
 const JSClass* MozjsNumericTypesTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
index 4dbc0b3..286a091 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
@@ -482,7 +482,10 @@
 // static
 JSObject* MozjsObjectTypeBindingsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -501,7 +504,10 @@
 //static
 const JSClass* MozjsObjectTypeBindingsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
index 7d9c1b0..20a6a3c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
@@ -1565,7 +1565,10 @@
 // static
 JSObject* MozjsOperationsTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -1584,7 +1587,10 @@
 //static
 const JSClass* MozjsOperationsTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
index c632988..12b04af 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
@@ -409,7 +409,10 @@
 // static
 JSObject* MozjsPutForwardsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -428,7 +431,10 @@
 //static
 const JSClass* MozjsPutForwardsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
index f07d2b5..38b509c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
@@ -50,45 +50,52 @@
     JSContext* context,
     JS::HandleObject implementing_object)
     : context_(context),
-      implementing_object_(implementing_object) { }
+      implementing_object_(context, implementing_object) { }
 
 base::optional<int32_t > MozjsSingleOperationInterface::HandleCallback(
     const scoped_refptr<script::Wrappable>& callback_this,
     const scoped_refptr<ArbitraryInterface>& value,
     bool* had_exception) const {
-  JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_compartment(context_, implementing_object_);
-
   bool success = false;
   base::optional<int32_t > cobalt_return_value;
-  // Get callable object.
-  JS::RootedValue callable(context_);
-  if (GetCallableForCallbackInterface(context_, implementing_object_,
-                                      "handleCallback", &callable)) {
-    // Convert the callback_this to a JSValue.
-    JS::RootedValue this_value(context_);
-    ToJSValue(context_, callback_this, &this_value);
 
-    // Convert arguments.
-    const int kNumArguments = 1;
-    JS::Value args[kNumArguments];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, value,
-              auto_array_rooter.handleAt(0));
+  // This could be set to NULL if it was garbage collected.
+  JS::RootedObject implementing_object(context_, implementing_object_.Get());
+  DLOG_IF(WARNING, !implementing_object) << "Implementing object is NULL.";
+  if (implementing_object) {
+    JSAutoRequest auto_request(context_);
+    JSAutoCompartment auto_compartment(context_, implementing_object);
 
-    // Call the function.
-    JS::RootedValue return_value(context_);
-    JSFunction* function = JS_ValueToFunction(context_, callable);
-    DCHECK(function);
-    success = JS::Call(context_, this_value, function, kNumArguments, args,
-                       return_value.address());
-    DLOG_IF(WARNING, !success) << "Exception in callback.";
-    if (success) {
-      LoggingExceptionState exception_state;
-      FromJSValue(context_, return_value, 0, &exception_state,
-                  &cobalt_return_value);
-      success = !exception_state.is_exception_set();
+    // Get callable object.
+    JS::RootedValue callable(context_);
+    if (GetCallableForCallbackInterface(context_, implementing_object,
+                                        "handleCallback", &callable)) {
+      // Convert the callback_this to a JSValue.
+      JS::RootedValue this_value(context_);
+      ToJSValue(context_, callback_this, &this_value);
+
+      // Convert arguments.
+      const int kNumArguments = 1;
+      JS::Value args[kNumArguments];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, value,
+                auto_array_rooter.handleAt(0));
+
+      // Call the function.
+      JS::RootedValue return_value(context_);
+      JS::RootedFunction function(
+          context_, JS_ValueToFunction(context_, callable));
+      DCHECK(function);
+      success = JS::Call(context_, this_value, function, kNumArguments, args,
+                         return_value.address());
+      DLOG_IF(WARNING, !success) << "Exception in callback.";
+      if (success) {
+        LoggingExceptionState exception_state;
+        FromJSValue(context_, return_value, 0, &exception_state,
+                    &cobalt_return_value);
+        success = !exception_state.is_exception_set();
+      }
     }
   }
 
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.h
index f2bb3be..65400a2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.h
@@ -26,6 +26,7 @@
 // Headers for other bindings wrapper classes
 #include "cobalt/bindings/testing/single_operation_interface.h"
 
+#include "cobalt/script/mozjs/weak_heap_object.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 
 namespace cobalt {
@@ -42,11 +43,11 @@
       const scoped_refptr<script::Wrappable>& callback_this,
       const scoped_refptr<ArbitraryInterface>& value,
       bool* had_exception) const OVERRIDE;
-  JSObject* handle() const { return implementing_object_; }
+  JSObject* handle() const { return implementing_object_.Get(); }
 
  private:
   JSContext* context_;
-  JS::Heap<JSObject*> implementing_object_;
+  script::mozjs::WeakHeapObject implementing_object_;
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
index 7cd708f..fe8a2ad 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
@@ -591,7 +591,10 @@
 // static
 JSObject* MozjsStaticPropertiesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -610,7 +613,10 @@
 //static
 const JSClass* MozjsStaticPropertiesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
index 2471dfc..bf5fab5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
@@ -331,7 +331,10 @@
 // static
 JSObject* MozjsStringifierAnonymousOperationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -350,7 +353,10 @@
 //static
 const JSClass* MozjsStringifierAnonymousOperationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
index f97b025..e7ab56b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
@@ -381,7 +381,10 @@
 // static
 JSObject* MozjsStringifierAttributeInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -400,7 +403,10 @@
 //static
 const JSClass* MozjsStringifierAttributeInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
index 3a96a4b..915226a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
@@ -372,7 +372,10 @@
 // static
 JSObject* MozjsStringifierOperationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -391,7 +394,10 @@
 //static
 const JSClass* MozjsStringifierOperationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
index 49786d1..3f3110e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
@@ -362,7 +362,10 @@
 // static
 JSObject* MozjsTargetInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -381,7 +384,10 @@
 //static
 const JSClass* MozjsTargetInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
index bc19f25..df03fdc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
@@ -500,7 +500,10 @@
 // static
 JSObject* MozjsUnionTypesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -519,7 +522,10 @@
 //static
 const JSClass* MozjsUnionTypesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
index f52bcf2..a2f79de 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
@@ -643,9 +643,6 @@
   JSAutoCompartment auto_compartment(context, global_object);
   bool success = JS_InitStandardClasses(context, global_object);
 
-  JS::RootedObject parent_prototype(
-      context, JS_GetObjectPrototype(context, global_object));
-
   JS::RootedObject prototype(
       context, MozjsWindow::GetPrototype(context, global_object));
   DCHECK(prototype);
@@ -671,7 +668,10 @@
 //static
 const JSClass* MozjsWindow::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
index 421cddb..3a668f8 100644
--- a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
@@ -42,7 +42,7 @@
     JSContext* context,
     JS::HandleObject implementing_object)
     : context_(context),
-      implementing_object_(implementing_object) { }
+      implementing_object_(context, implementing_object) { }
 
 {% for operation in operations %}
 {% for overload in operation.overloads %}
@@ -52,46 +52,53 @@
     {{arg.arg_type}} {{arg.name}},
   {% endfor %}
     bool* had_exception) const {
-  JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_compartment(context_, implementing_object_);
-
   bool success = false;
 {% if overload.type != 'void' %}
   {{overload.type}} cobalt_return_value;
 {% endif %}
-  // Get callable object.
-  JS::RootedValue callable(context_);
-  if (GetCallableForCallbackInterface(context_, implementing_object_,
-                                      "{{overload.idl_name}}", &callable)) {
-    // Convert the callback_this to a JSValue.
-    JS::RootedValue this_value(context_);
-    ToJSValue(context_, callback_this, &this_value);
 
-    // Convert arguments.
-    const int kNumArguments = {{overload.arguments|length}};
-    JS::Value args[kNumArguments];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    {% for arg in overload.arguments %}
-    ToJSValue(context_, {{arg.name}},
-              auto_array_rooter.handleAt({{loop.index0}}));
-    {% endfor %}
+  // This could be set to NULL if it was garbage collected.
+  JS::RootedObject implementing_object(context_, implementing_object_.Get());
+  DLOG_IF(WARNING, !implementing_object) << "Implementing object is NULL.";
+  if (implementing_object) {
+    JSAutoRequest auto_request(context_);
+    JSAutoCompartment auto_compartment(context_, implementing_object);
 
-    // Call the function.
-    JS::RootedValue return_value(context_);
-    JSFunction* function = JS_ValueToFunction(context_, callable);
-    DCHECK(function);
-    success = JS::Call(context_, this_value, function, kNumArguments, args,
-                       return_value.address());
-    DLOG_IF(WARNING, !success) << "Exception in callback.";
+    // Get callable object.
+    JS::RootedValue callable(context_);
+    if (GetCallableForCallbackInterface(context_, implementing_object,
+                                        "{{overload.idl_name}}", &callable)) {
+      // Convert the callback_this to a JSValue.
+      JS::RootedValue this_value(context_);
+      ToJSValue(context_, callback_this, &this_value);
+
+      // Convert arguments.
+      const int kNumArguments = {{overload.arguments|length}};
+      JS::Value args[kNumArguments];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+{% for arg in overload.arguments %}
+      ToJSValue(context_, {{arg.name}},
+                auto_array_rooter.handleAt({{loop.index0}}));
+{% endfor %}
+
+      // Call the function.
+      JS::RootedValue return_value(context_);
+      JS::RootedFunction function(
+          context_, JS_ValueToFunction(context_, callable));
+      DCHECK(function);
+      success = JS::Call(context_, this_value, function, kNumArguments, args,
+                         return_value.address());
+      DLOG_IF(WARNING, !success) << "Exception in callback.";
 {% if overload.type != 'void' %}
-    if (success) {
-      LoggingExceptionState exception_state;
-      FromJSValue(context_, return_value, 0, &exception_state,
-                  &cobalt_return_value);
-      success = !exception_state.is_exception_set();
-    }
+      if (success) {
+        LoggingExceptionState exception_state;
+        FromJSValue(context_, return_value, 0, &exception_state,
+                    &cobalt_return_value);
+        success = !exception_state.is_exception_set();
+      }
 {% endif %}
+    }
   }
 
   *had_exception = !success;
diff --git a/src/cobalt/bindings/mozjs/templates/callback-interface.h.template b/src/cobalt/bindings/mozjs/templates/callback-interface.h.template
index 1cfeb00..0364b98 100644
--- a/src/cobalt/bindings/mozjs/templates/callback-interface.h.template
+++ b/src/cobalt/bindings/mozjs/templates/callback-interface.h.template
@@ -17,6 +17,7 @@
 
 {% block includes %}
 {{ super() }}
+#include "cobalt/script/mozjs/weak_heap_object.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 {% endblock includes %}
 
@@ -42,11 +43,11 @@
       bool* had_exception) const OVERRIDE;
 {% endfor %}
 {% endfor %}
-  JSObject* handle() const { return implementing_object_; }
+  JSObject* handle() const { return implementing_object_.Get(); }
 
  private:
   JSContext* context_;
-  JS::Heap<JSObject*> implementing_object_;
+  script::mozjs::WeakHeapObject implementing_object_;
 };
 
 {% for component in components %}
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 16134d5..4d4c20e 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -664,25 +664,22 @@
   {% if parent_interface %}
   JS::RootedObject parent_prototype(
       context, {{parent_interface}}::GetPrototype(context, global_object));
+  {% elif is_exception_interface %}
+  // Get Error prototype.
+  JS::RootedObject parent_prototype(context);
+  bool success_check = js_GetClassPrototype(
+      context, GetExceptionProtoKey(JSEXN_ERR), &parent_prototype);
+  DCHECK(success_check);
   {% else %}
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   {% endif %}
   DCHECK(parent_prototype);
 
-{% if is_exception_interface %}
-  JS::RootedObject prototype(context);
-  // Get Error prototype.
-  bool success_check = js_GetClassPrototype(
-      context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
-  DCHECK(success_check);
-  interface_data->prototype = prototype;
-{% else %}
   // Create the Prototype object.
   interface_data->prototype = JS_NewObjectWithGivenProto(
       context, &interface_data->prototype_class_definition, parent_prototype,
       NULL);
-{% endif %}
   bool success = JS_DefineProperties(
       context, interface_data->prototype, prototype_properties);
   DCHECK(success);
@@ -779,9 +776,6 @@
   JSAutoCompartment auto_compartment(context, global_object);
   bool success = JS_InitStandardClasses(context, global_object);
 
-  JS::RootedObject parent_prototype(
-      context, JS_GetObjectPrototype(context, global_object));
-
   JS::RootedObject prototype(
       context, {{binding_class}}::GetPrototype(context, global_object));
   DCHECK(prototype);
@@ -808,7 +802,10 @@
 // static
 JSObject* {{binding_class}}::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   InterfaceData* interface_data = GetInterfaceData(context);
@@ -828,7 +825,10 @@
 //static
 const JSClass* {{binding_class}}::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
   DCHECK(global_object);
 
   JS::RootedObject prototype(context, GetPrototype(context, global_object));
diff --git a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
index 88e92d0..ab0546a 100644
--- a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
+++ b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
@@ -308,7 +308,7 @@
   if (TypeParam::min_value() >= 0) {
     expected_result = "18446744073709550000";
     EXPECT_CALL(this->test_mock(), MockReturnValueOperation())
-        .WillOnce(Return(18446744073709550000l));
+        .WillOnce(Return(18446744073709550000ull));
     EXPECT_TRUE(this->EvaluateScript(script, &result));
     EXPECT_STREQ(expected_result.c_str(), result.c_str());
   }
@@ -363,7 +363,7 @@
   // Unsigned : send 18446744073709550000 (between 2^53
   // and uint64_t max) to 18446744073709549568.
   if (TypeParam::min_value() >= 0) {
-    EXPECT_CALL(this->test_mock(), mock_set_property(18446744073709549568));
+    EXPECT_CALL(this->test_mock(), mock_set_property(18446744073709549568ull));
     EXPECT_TRUE(this->EvaluateScript(
         StringPrintf("test.%sProperty = 18446744073709550000;",
                      TypeParam::type_string()),
@@ -408,7 +408,8 @@
   // Unsigned : send 18446744073709550000 (between 2^53
   // and uint64_t max) to 18446744073709549568.
   if (TypeParam::min_value() >= 0) {
-    EXPECT_CALL(this->test_mock(), MockArgumentOperation(18446744073709549568));
+    EXPECT_CALL(this->test_mock(),
+                MockArgumentOperation(18446744073709549568ull));
     EXPECT_TRUE(this->EvaluateScript(
         StringPrintf("test.%sArgumentOperation(18446744073709550000);",
                      TypeParam::type_string()),
diff --git a/src/cobalt/bindings/testing/numeric_types_test_interface.h b/src/cobalt/bindings/testing/numeric_types_test_interface.h
index 713dea5..5730662 100644
--- a/src/cobalt/bindings/testing/numeric_types_test_interface.h
+++ b/src/cobalt/bindings/testing/numeric_types_test_interface.h
@@ -246,7 +246,7 @@
 
   static const char* type_string() { return "unsignedLongLong"; }
 
-  static uint64_t max_value() { return 18446744073709551615; }
+  static uint64_t max_value() { return 18446744073709551615ull; }
   static uint64_t min_value() { return 0; }
   // This is what the value 18446744073709551615 maps to in javascript.
   static const char* max_value_string() { return "18446744073709552000"; }
diff --git a/src/cobalt/bindings/testing/stack_trace_test.cc b/src/cobalt/bindings/testing/stack_trace_test.cc
index c9e39a8..34c4629 100644
--- a/src/cobalt/bindings/testing/stack_trace_test.cc
+++ b/src/cobalt/bindings/testing/stack_trace_test.cc
@@ -16,6 +16,8 @@
 
 #include "cobalt/bindings/testing/bindings_test_base.h"
 
+using ::testing::MatchesRegex;
+
 namespace cobalt {
 namespace bindings {
 namespace testing {
@@ -45,15 +47,15 @@
   EXPECT_TRUE(EvaluateScript(script, &result));
 
   // Expect that bar is on top.
-  std::string match_line = "bar @ [object BindingsTestBase]:2\n";
+  std::string match_line = "bar @ [object BindingsTestBase]:2";
   size_t position = result.find(match_line);
   EXPECT_TRUE(position != std::string::npos);
   // Expect a foo at line 6.
-  match_line = "foo @ [object BindingsTestBase]:6\n";
+  match_line = "foo @ [object BindingsTestBase]:6";
   position = result.find(match_line, ++position);
   EXPECT_TRUE(position != std::string::npos);
   // Expect 4 subsequent foos at line 8.
-  match_line = "foo @ [object BindingsTestBase]:8\n";
+  match_line = "foo @ [object BindingsTestBase]:8";
   for (int i = 0; i < 4; ++i) {
     position = result.find(match_line, ++position);
     EXPECT_TRUE(position != std::string::npos);
@@ -64,6 +66,30 @@
   EXPECT_TRUE(position != std::string::npos);
 }
 
+#if defined(ENGINE_SUPPORTS_STACK_TRACE_COLUMNS)
+// Test for column numbers in stack trace. Behavior varies somewhat
+// across engines & versions so, don't check actual column values.
+TEST_F(StackTraceTest, GetStackTraceColumns) {
+  std::string result;
+
+  const std::string script =
+      "function bar() {\n"
+      "// Add extra statements to shift the error right.\n"
+      "  var x; var y; return getStackTrace(); var z;\n"
+      "}\n"
+      "function multiArg(in1, in2) {\n"
+      "  return in2;\n"
+      "}\n"
+      "multiArg(0, bar());";
+
+  EXPECT_TRUE(EvaluateScript(script, &result));
+  const std::string expected =
+      "bar @ \\[object BindingsTestBase\\]:3:\\d+\n"
+      "global code @ \\[object BindingsTestBase\\]:8:\\d+";
+  EXPECT_THAT(result, MatchesRegex(expected));
+}
+#endif  // ENGINE_SUPPORTS_STACK_TRACE_COLUMNS
+
 }  // namespace testing
 }  // namespace bindings
 }  // namespace cobalt
diff --git a/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp b/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp
index b9f074d..f212dcf 100644
--- a/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp
+++ b/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp
@@ -105,6 +105,7 @@
 ../dom/Uint32Array.idl
 ../dom/Uint8Array.idl
 ../dom/URL.idl
+../dom/VideoPlaybackQuality.idl
 ../dom/Window.idl
 ../dom/XMLDocument.idl
 ../dom/XMLSerializer.idl
diff --git a/src/cobalt/browser/global_objects_idl_files_list.tmp b/src/cobalt/browser/global_objects_idl_files_list.tmp
index b9f074d..f212dcf 100644
--- a/src/cobalt/browser/global_objects_idl_files_list.tmp
+++ b/src/cobalt/browser/global_objects_idl_files_list.tmp
@@ -105,6 +105,7 @@
 ../dom/Uint32Array.idl
 ../dom/Uint8Array.idl
 ../dom/URL.idl
+../dom/VideoPlaybackQuality.idl
 ../dom/Window.idl
 ../dom/XMLDocument.idl
 ../dom/XMLSerializer.idl
diff --git a/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp b/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp
index 86c81b6..e4de45c 100644
--- a/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp
+++ b/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp
@@ -105,6 +105,7 @@
 ../dom/Uint32Array.idl
 ../dom/Uint8Array.idl
 ../dom/URL.idl
+../dom/VideoPlaybackQuality.idl
 ../dom/Window.idl
 ../dom/XMLDocument.idl
 ../dom/XMLSerializer.idl
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 828380d..307b437 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -542,6 +542,9 @@
 #if defined(ADDRESS_SANITIZER)
   // ASAN requires a much bigger stack size here.
   const int kStackSize = 4096 * 1024;
+#elif defined(COBALT_BUILD_TYPE_DEBUG)
+  // Non-optimized builds require a bigger stack size.
+  const int kStackSize = 2 * 1024 * 1024;
 #else
   const int kStackSize = 256 * 1024;
 #endif
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 29fb020..f8231a2 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-10060
\ No newline at end of file
+10363
\ No newline at end of file
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y
index be1ffdd..09e7f2d 100644
--- a/src/cobalt/css_parser/grammar.y
+++ b/src/cobalt/css_parser/grammar.y
@@ -2381,8 +2381,7 @@
         break;
       }
       default:
-        parser_impl->LogWarning(@1, "invalid color value");
-        $$ = NULL;
+        YYERROR;
         break;
     }
   }
diff --git a/src/cobalt/css_parser/parser_test.cc b/src/cobalt/css_parser/parser_test.cc
index a64f963..77b4874 100644
--- a/src/cobalt/css_parser/parser_test.cc
+++ b/src/cobalt/css_parser/parser_test.cc
@@ -1366,6 +1366,20 @@
             style->GetPropertyValue(cssom::kBackgroundImageProperty));
 }
 
+TEST_F(ParserTest, LinearGradientWithInvalidColorStopIsError) {
+  EXPECT_CALL(
+      parser_observer_,
+      OnWarning("[object ParserTest]:1:11: warning: unsupported value"));
+
+  scoped_refptr<cssom::CSSDeclaredStyleData> style =
+      parser_.ParseStyleDeclarationList(
+          "background: linear-gradient(#0123456789abcde 0%));",
+          source_location_);
+
+  EXPECT_EQ(GetPropertyInitialValue(cssom::kBackgroundImageProperty),
+            style->GetPropertyValue(cssom::kBackgroundImageProperty));
+}
+
 TEST_F(ParserTest, RadialGradientWithOneColorStopIsError) {
   EXPECT_CALL(
       parser_observer_,
diff --git a/src/cobalt/cssom/computed_style.cc b/src/cobalt/cssom/computed_style.cc
index 48d8223..ea15228 100644
--- a/src/cobalt/cssom/computed_style.cc
+++ b/src/cobalt/cssom/computed_style.cc
@@ -1631,7 +1631,7 @@
 
   size_t size = specified_position->value().size();
   DCHECK_GE(size, 1u);
-  DCHECK_LE(size, 2u);
+  DCHECK_LE(size, 4u);
 
   ComputedPositionHelper position_helper(
       computed_font_size, root_computed_font_size, viewport_size);
diff --git a/src/cobalt/cssom/computed_style_test.cc b/src/cobalt/cssom/computed_style_test.cc
index d499787..2637dfa 100644
--- a/src/cobalt/cssom/computed_style_test.cc
+++ b/src/cobalt/cssom/computed_style_test.cc
@@ -48,6 +48,24 @@
   return computed_style_declaration;
 }
 
+TEST(PromoteToComputedStyle, UnknownPropertyValueShouldBeEmpty) {
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> computed_style_declaration(
+      CreateComputedStyleDeclaration(computed_style));
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         parent_computed_style, math::Size(), NULL);
+
+  EXPECT_EQ(
+      computed_style_declaration->GetPropertyValue("cobalt_cobalt_cobalt"), "");
+}
+
 TEST(PromoteToComputedStyle, FontWeightShouldBeBoldAsSpecified) {
   scoped_refptr<CSSComputedStyleData> computed_style(
       new CSSComputedStyleData());
diff --git a/src/cobalt/cssom/css_computed_style_data.cc b/src/cobalt/cssom/css_computed_style_data.cc
index 590ea05..a5e2fcd 100644
--- a/src/cobalt/cssom/css_computed_style_data.cc
+++ b/src/cobalt/cssom/css_computed_style_data.cc
@@ -104,6 +104,8 @@
 
 scoped_refptr<PropertyValue>&
 CSSComputedStyleData::GetDeclaredPropertyValueReference(PropertyKey key) {
+  DCHECK_GT(key, kNoneProperty);
+  DCHECK_LE(key, kMaxLonghandPropertyKey);
   DCHECK(declared_properties_[key]);
   return declared_property_values_.find(key)->second;
 }
@@ -329,6 +331,8 @@
 
 void CSSComputedStyleData::AddDeclaredPropertyInheritedFromParent(
     PropertyKey key) {
+  DCHECK_GT(key, kNoneProperty);
+  DCHECK_LE(key, kMaxLonghandPropertyKey);
   declared_properties_inherited_from_parent_.push_back(key);
 }
 
diff --git a/src/cobalt/cssom/css_computed_style_declaration.cc b/src/cobalt/cssom/css_computed_style_declaration.cc
index 11c7dbb..ed4b4c8 100644
--- a/src/cobalt/cssom/css_computed_style_declaration.cc
+++ b/src/cobalt/cssom/css_computed_style_declaration.cc
@@ -56,7 +56,7 @@
 
 std::string CSSComputedStyleDeclaration::GetDeclaredPropertyValueStringByKey(
     const PropertyKey key) const {
-  if (!data_) {
+  if (!data_ || key == kNoneProperty) {
     return std::string();
   }
   const scoped_refptr<PropertyValue>& property_value =
diff --git a/src/cobalt/cssom/css_declared_style_data.cc b/src/cobalt/cssom/css_declared_style_data.cc
index 6b96bd3..6768e50 100644
--- a/src/cobalt/cssom/css_declared_style_data.cc
+++ b/src/cobalt/cssom/css_declared_style_data.cc
@@ -45,7 +45,7 @@
 }
 
 bool CSSDeclaredStyleData::IsSupportedPropertyKey(PropertyKey key) const {
-  return key >= kNoneProperty && key <= kMaxLonghandPropertyKey;
+  return key > kNoneProperty && key <= kMaxLonghandPropertyKey;
 }
 
 scoped_refptr<PropertyValue> CSSDeclaredStyleData::GetPropertyValue(
diff --git a/src/cobalt/cssom/css_declared_style_declaration.cc b/src/cobalt/cssom/css_declared_style_declaration.cc
index 9774686..c1d455c 100644
--- a/src/cobalt/cssom/css_declared_style_declaration.cc
+++ b/src/cobalt/cssom/css_declared_style_declaration.cc
@@ -105,7 +105,8 @@
 
 std::string CSSDeclaredStyleDeclaration::GetDeclaredPropertyValueStringByKey(
     const PropertyKey key) const {
-  return data_ ? data_->GetPropertyValueString(key) : std::string();
+  return (data_ && key != kNoneProperty) ? data_->GetPropertyValueString(key)
+                                         : std::string();
 }
 
 void CSSDeclaredStyleDeclaration::SetPropertyValue(
diff --git a/src/cobalt/cssom/css_style_declaration_test.cc b/src/cobalt/cssom/css_style_declaration_test.cc
index fe62b27..0e71d24 100644
--- a/src/cobalt/cssom/css_style_declaration_test.cc
+++ b/src/cobalt/cssom/css_style_declaration_test.cc
@@ -1387,6 +1387,16 @@
             "center");
 }
 
+TEST(CSSStyleDeclarationTest, UnknownDeclaredStylePropertyValueShouldBeEmpty) {
+  testing::MockCSSParser css_parser;
+  scoped_refptr<CSSDeclaredStyleData> initial_style =
+      new CSSDeclaredStyleData();
+  scoped_refptr<CSSDeclaredStyleDeclaration> style =
+      new CSSDeclaredStyleDeclaration(initial_style, &css_parser);
+
+  EXPECT_EQ(style->GetPropertyValue("cobalt_cobalt_cobalt"), "");
+}
+
 TEST(CSSStyleDeclarationTest, LengthAttributeGetterEmpty) {
   testing::MockCSSParser css_parser;
   scoped_refptr<CSSDeclaredStyleDeclaration> style =
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 0d2b543..0a294ac 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -444,6 +444,11 @@
   are_font_faces_dirty_ = true;
   are_keyframes_dirty_ = true;
 
+  scoped_refptr<HTMLHtmlElement> current_html = html();
+  if (current_html) {
+    current_html->InvalidateComputedStylesRecursively();
+  }
+
   RecordMutation();
 }
 
diff --git a/src/cobalt/dom/dom_parser.cc b/src/cobalt/dom/dom_parser.cc
index feebac7..c70d4e2 100644
--- a/src/cobalt/dom/dom_parser.cc
+++ b/src/cobalt/dom/dom_parser.cc
@@ -47,8 +47,9 @@
     case kImageSvgXml:
       return html_element_context_->dom_parser()->ParseXMLDocument(
           str, GetInlineSourceLocation());
+    case kMaxSupportedType:
     default:
-      NOTREACHED();
+      LOG(WARNING) << "DOMParse.ParseFromString received invalid type value.";
       return NULL;
   }
 }
diff --git a/src/cobalt/dom/dom_parser.h b/src/cobalt/dom/dom_parser.h
index 946121a..975097a 100644
--- a/src/cobalt/dom/dom_parser.h
+++ b/src/cobalt/dom/dom_parser.h
@@ -41,6 +41,7 @@
     kApplicationXml,
     kApplicationXhtmlXml,
     kImageSvgXml,
+    kMaxSupportedType,
   };
 
   explicit DOMParser(script::EnvironmentSettings* environment_settings);
diff --git a/src/cobalt/dom/dom_parser_test.cc b/src/cobalt/dom/dom_parser_test.cc
index 3f1705c..5d392e1 100644
--- a/src/cobalt/dom/dom_parser_test.cc
+++ b/src/cobalt/dom/dom_parser_test.cc
@@ -73,5 +73,11 @@
   EXPECT_TRUE(document->IsXMLDocument());
 }
 
+TEST_F(DOMParserTest, InvalidType) {
+  scoped_refptr<Document> document =
+      dom_parser_->ParseFromString("", DOMParser::kMaxSupportedType);
+  EXPECT_FALSE(document);
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index f63dbbf..0d57ebd 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -618,13 +618,7 @@
 
 void HTMLElement::InvalidateComputedStylesRecursively() {
   computed_style_valid_ = false;
-
-  for (Element* element = first_element_child(); element;
-       element = element->next_element_sibling()) {
-    HTMLElement* html_element = element->AsHTMLElement();
-    DCHECK(html_element);
-    html_element->InvalidateComputedStylesRecursively();
-  }
+  Node::InvalidateComputedStylesRecursively();
 }
 
 void HTMLElement::UpdateComputedStyleRecursively(
@@ -713,6 +707,7 @@
 HTMLElement::~HTMLElement() {
   --(non_trivial_static_fields.Get().html_element_count_log.count);
   dom_stat_tracker_->OnHtmlElementDestroyed();
+  style_->set_mutation_observer(NULL);
 }
 
 void HTMLElement::CopyDirectionality(const HTMLElement& other) {
@@ -1068,6 +1063,7 @@
 
 void HTMLElement::OnBackgroundImageLoaded() {
   node_document()->RecordMutation();
+  InvalidateRenderTreeNodesFromNode();
 }
 
 bool HTMLElement::IsRootElement() {
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index 11837a8..5e7fcae 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -201,7 +201,7 @@
   }
 
   // Invalidates the cached computed style of this element and its descendants.
-  void InvalidateComputedStylesRecursively();
+  void InvalidateComputedStylesRecursively() OVERRIDE;
   // Updates the cached computed style of this element and its descendants.
   void UpdateComputedStyleRecursively(
       const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
diff --git a/src/cobalt/dom/html_link_element.cc b/src/cobalt/dom/html_link_element.cc
index e101525..fd85733 100644
--- a/src/cobalt/dom/html_link_element.cc
+++ b/src/cobalt/dom/html_link_element.cc
@@ -57,6 +57,15 @@
   TRACE_EVENT0("cobalt::dom", "HTMLLinkElement::Obtain()");
   // Custom, not in any spec.
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  Document* document = node_document();
+
+  // If the document has no browsing context, do not obtain, parse or apply the
+  // style sheet.
+  if (!document->html_element_context()) {
+    return;
+  }
+
   DCHECK(MessageLoop::current());
   DCHECK(!loader_);
 
@@ -78,7 +87,6 @@
   // the mode being the current state of the element's crossorigin content
   // attribute, the origin being the origin of the link element's Document, and
   // the default origin behaviour set to taint.
-  Document* document = node_document();
   csp::SecurityCallback csp_callback = base::Bind(
       &CspDelegate::CanLoad, base::Unretained(document->csp_delegate()),
       CspDelegate::kStyle);
@@ -100,7 +108,6 @@
 
 void HTMLLinkElement::OnLoadingDone(const std::string& content) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(rel(), "stylesheet");
   TRACE_EVENT0("cobalt::dom", "HTMLLinkElement::OnLoadingDone()");
 
   Document* document = node_document();
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index f4f04bb..12a4e8e 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -638,6 +638,13 @@
 
   GURL url = initial_url;
 
+  if (!url.is_valid()) {
+    // Try to filter out invalid urls as GURL::spec() DCHECKs if the url is
+    // valid.
+    NoneSupported();
+    return;
+  }
+
   DCHECK(!media_source_);
   if (url.SchemeIs(kMediaSourceUrlProtocol)) {
     // Check whether url is allowed by security policy.
@@ -1186,7 +1193,7 @@
 }
 
 void HTMLMediaElement::ConfigureMediaControls() {
-  DCHECK(!controls_) << "media control is not supported";
+  DLOG_IF(WARNING, controls_) << "media control is not supported";
 }
 
 void HTMLMediaElement::MediaEngineError(scoped_refptr<MediaError> error) {
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc
index 09004f7..16acbde 100644
--- a/src/cobalt/dom/html_script_element.cc
+++ b/src/cobalt/dom/html_script_element.cc
@@ -76,6 +76,18 @@
   return this;
 }
 
+scoped_refptr<Node> HTMLScriptElement::Duplicate() const {
+  // The cloning steps for script elements must set the "already started" flag
+  // on the copy if it is set on the element being cloned.
+  //   https://www.w3.org/TR/html5/scripting-1.html#already-started
+  scoped_refptr<HTMLScriptElement> new_script = HTMLElement::Duplicate()
+                                                    ->AsElement()
+                                                    ->AsHTMLElement()
+                                                    ->AsHTMLScriptElement();
+  new_script->is_already_started_ = is_already_started_;
+  return new_script;
+}
+
 HTMLScriptElement::~HTMLScriptElement() {
   // Remove the script from the list of scripts that will execute in order as
   // soon as possible associated with the Document, only if the document still
diff --git a/src/cobalt/dom/html_script_element.h b/src/cobalt/dom/html_script_element.h
index 91fe882..9335314 100644
--- a/src/cobalt/dom/html_script_element.h
+++ b/src/cobalt/dom/html_script_element.h
@@ -77,6 +77,9 @@
 
   DEFINE_WRAPPABLE_TYPE(HTMLScriptElement);
 
+ protected:
+  scoped_refptr<Node> Duplicate() const OVERRIDE;
+
  private:
   ~HTMLScriptElement() OVERRIDE;
 
diff --git a/src/cobalt/dom/html_style_element.cc b/src/cobalt/dom/html_style_element.cc
index a529cc9..88a5626 100644
--- a/src/cobalt/dom/html_style_element.cc
+++ b/src/cobalt/dom/html_style_element.cc
@@ -56,6 +56,13 @@
 
 void HTMLStyleElement::Process() {
   Document* document = node_document();
+
+  // If the document has no browsing context, do not parse or apply the style
+  // sheet.
+  if (!document->html_element_context()) {
+    return;
+  }
+
   CspDelegate* csp_delegate = document->csp_delegate();
   // If the style element has a valid nonce, we always permit it.
   const bool bypass_csp = csp_delegate->IsValidNonce(
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index cf81ef0..041836c 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -402,6 +402,7 @@
 Node::~Node() {
   Node* node = last_child_;
   while (node) {
+    node->parent_ = NULL;
     node->next_sibling_ = NULL;
     node = node->previous_sibling_;
   }
@@ -432,6 +433,14 @@
   }
 }
 
+void Node::InvalidateComputedStylesRecursively() {
+  Node* child = first_child_;
+  while (child) {
+    child->InvalidateComputedStylesRecursively();
+    child = child->next_sibling_;
+  }
+}
+
 void Node::InvalidateLayoutBoxesFromNodeAndAncestors() {
   if (parent_) {
     parent_->InvalidateLayoutBoxesFromNodeAndAncestors();
@@ -566,9 +575,14 @@
   // Custom, not in any spec.
 
   OnMutation();
-  InvalidateLayoutBoxesFromNodeAndAncestors();
   node->UpdateGenerationForNodeAndAncestors();
 
+  // Invalidate the layout boxes of the new parent as a result of its children
+  // being changed.
+  // NOTE: The added node does not have any invalidations done, because they
+  // occur on the remove and are guaranteed to not be needed at this point.
+  InvalidateLayoutBoxesFromNodeAndAncestors();
+
   if (inserted_into_document_) {
     node->OnInsertedIntoDocument();
     Document* document = node_document();
@@ -600,10 +614,17 @@
   DCHECK(node);
 
   OnMutation();
-  InvalidateLayoutBoxesFromNodeAndAncestors();
-  node->InvalidateLayoutBoxesFromNodeAndDescendants();
   node->UpdateGenerationForNodeAndAncestors();
 
+  // Invalidate the layout boxes of the previous parent as a result of its
+  // children being changed.
+  InvalidateLayoutBoxesFromNodeAndAncestors();
+  // Invalidate the styles and layout boxes of the node being removed from
+  // the tree. These are no longer valid as a result of the child and its
+  // descendants losing their inherited styles.
+  node->InvalidateComputedStylesRecursively();
+  node->InvalidateLayoutBoxesFromNodeAndDescendants();
+
   bool was_inserted_to_document = node->inserted_into_document_;
   if (was_inserted_to_document) {
     node->OnRemovedFromDocument();
diff --git a/src/cobalt/dom/node.h b/src/cobalt/dom/node.h
index 0b2ca54..0c2a4f6 100644
--- a/src/cobalt/dom/node.h
+++ b/src/cobalt/dom/node.h
@@ -231,6 +231,8 @@
   // removed from to its owner document.
   virtual void OnRemovedFromDocument();
 
+  // Invalidate computed styles from this node and all child nodes.
+  virtual void InvalidateComputedStylesRecursively();
   // Invalidate layout boxes from this node and all parent nodes.
   virtual void InvalidateLayoutBoxesFromNodeAndAncestors();
   // Invalidate layout boxes from this node and all child nodes.
diff --git a/src/cobalt/dom/test_runner.cc b/src/cobalt/dom/test_runner.cc
index c81aded..f838050 100644
--- a/src/cobalt/dom/test_runner.cc
+++ b/src/cobalt/dom/test_runner.cc
@@ -24,21 +24,21 @@
 TestRunner::TestRunner() : should_wait_(false) {}
 
 void TestRunner::NotifyDone() {
-  DCHECK(should_wait_);
-  should_wait_ = false;
-  if (!trigger_layout_callback_.is_null()) {
-    trigger_layout_callback_.Run();
+  if (should_wait_) {
+    should_wait_ = false;
+    if (!trigger_layout_callback_.is_null()) {
+      trigger_layout_callback_.Run();
+    }
+    // Reset |should_wait_| to prevent a second layout if the document onLoad
+    // event occurs after the layout trigger.
+    should_wait_ = true;
   }
-  // Reset |should_wait_| to prevent a second layout if the document onLoad
-  // event occurs after the layout trigger.
-  should_wait_ = true;
 }
 
 void TestRunner::WaitUntilDone() { should_wait_ = true; }
 
 void TestRunner::DoNonMeasuredLayout() {
-  DCHECK(should_wait_);
-  if (!trigger_layout_callback_.is_null()) {
+  if (should_wait_ && !trigger_layout_callback_.is_null()) {
     trigger_layout_callback_.Run();
   }
 }
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index 1f2d803..99f2b2c 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -325,9 +325,13 @@
   DCHECK(*paragraph_);
   int32 text_position = (*paragraph_)->GetTextEndPosition();
 
-  scoped_refptr<TextBox> br_text_box = new TextBox(
-      css_computed_style_declaration, *paragraph_, text_position, text_position,
-      true, context_->used_style_provider, context_->layout_stat_tracker);
+  const bool kTriggersLineBreakTrue = true;
+  const bool kIsProductOfSplitFalse = false;
+
+  scoped_refptr<TextBox> br_text_box =
+      new TextBox(css_computed_style_declaration, *paragraph_, text_position,
+                  text_position, kTriggersLineBreakTrue, kIsProductOfSplitFalse,
+                  context_->used_style_provider, context_->layout_stat_tracker);
 
   // Add a line feed code point to the paragraph to signify the new line for
   // the line breaking and bidirectional algorithms.
@@ -953,10 +957,12 @@
         (*paragraph_)->AppendUtf8String(modifiable_text, transform);
     int32 text_end_position = (*paragraph_)->GetTextEndPosition();
 
+    const bool kIsProductOfSplitFalse = false;
+
     boxes_.push_back(new TextBox(
         css_computed_style_declaration, *paragraph_, text_start_position,
-        text_end_position, generates_newline, context_->used_style_provider,
-        context_->layout_stat_tracker));
+        text_end_position, generates_newline, kIsProductOfSplitFalse,
+        context_->used_style_provider, context_->layout_stat_tracker));
 
     // Newline sequences should be transformed into a preserved line feed.
     //   https://www.w3.org/TR/css3-text/#line-break-transform
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc
index 1b4e96e..c0cb5fb 100644
--- a/src/cobalt/layout/text_box.cc
+++ b/src/cobalt/layout/text_box.cc
@@ -37,7 +37,7 @@
                      css_computed_style_declaration,
                  const scoped_refptr<Paragraph>& paragraph,
                  int32 text_start_position, int32 text_end_position,
-                 bool has_trailing_line_break,
+                 bool has_trailing_line_break, bool is_product_of_split,
                  UsedStyleProvider* used_style_provider,
                  LayoutStatTracker* layout_stat_tracker)
     : Box(css_computed_style_declaration, used_style_provider,
@@ -58,6 +58,7 @@
       should_collapse_leading_white_space_(false),
       should_collapse_trailing_white_space_(false),
       has_trailing_line_break_(has_trailing_line_break),
+      is_product_of_split_(is_product_of_split),
       update_size_results_valid_(false),
       ascent_(0) {
   DCHECK(text_start_position_ <= text_end_position_);
@@ -177,10 +178,19 @@
   }
 
   // Even when the text box's style prevents wrapping, wrapping can still occur
-  // before the box if the line's existence has already been justified and
-  // whitespace precedes the box.
+  // before the box if the following requirements are met:
+  // - The text box is not the product of a split. If it is, and this box's
+  //   style prevents text wrapping, then the previous box also prevents text
+  //   wrapping, and no wrap should occur between them.
+  // - The line's existence has already been justified. Wrapping cannot occur
+  //   prior to that.
+  // - Whitespace precedes the text box. This can only occur in the case where
+  //   the preceding box allows wrapping, otherwise a no-breaking space will
+  //   have been appended (the one exception to this is when this box was the
+  //   product of a split, but that case is already handled above).
   if (!DoesAllowTextWrapping(computed_style()->white_space())) {
-    if (is_line_existence_justified && text_start_position_ > 0 &&
+    if (!is_product_of_split_ && is_line_existence_justified &&
+        text_start_position_ > 0 &&
         paragraph_->IsCollapsibleWhiteSpace(text_start_position_ - 1)) {
       return kWrapResultWrapBefore;
     } else {
@@ -640,10 +650,12 @@
   update_size_results_valid_ = false;
   non_collapsible_text_width_ = base::nullopt;
 
+  const bool kIsProductOfSplitTrue = true;
+
   scoped_refptr<TextBox> box_after_split(new TextBox(
       css_computed_style_declaration(), paragraph_, split_start_position,
-      split_end_position, has_trailing_line_break_, used_style_provider(),
-      layout_stat_tracker()));
+      split_end_position, has_trailing_line_break_, kIsProductOfSplitTrue,
+      used_style_provider(), layout_stat_tracker()));
 
   // Update the split sibling links.
   box_after_split->split_sibling_ = split_sibling_;
diff --git a/src/cobalt/layout/text_box.h b/src/cobalt/layout/text_box.h
index dc55439..c7008eb 100644
--- a/src/cobalt/layout/text_box.h
+++ b/src/cobalt/layout/text_box.h
@@ -40,7 +40,7 @@
               css_computed_style_declaration,
           const scoped_refptr<Paragraph>& paragraph, int32 text_start_position,
           int32 text_end_position, bool triggers_line_break,
-          UsedStyleProvider* used_style_provider,
+          bool is_created_from_split, UsedStyleProvider* used_style_provider,
           LayoutStatTracker* layout_stat_tracker);
 
   // From |Box|.
@@ -180,6 +180,10 @@
   // A vertical offset of the baseline relatively to the origin of the text box.
   base::optional<LayoutUnit> baseline_offset_from_top_;
 
+  // Specifies whether or not this text box was created as a result of the split
+  // of a text box.
+  const bool is_product_of_split_;
+
   // A reference to the next text box in a linked list of text boxes produced
   // from splits of the initial text box. This enables HTMLElement to retain
   // access to all of its layout boxes after they are split.
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png
new file mode 100644
index 0000000..03e1d7a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap.html b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap.html
new file mode 100644
index 0000000..032c4e5
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!--
+ | The value "nowrap" of property "white-space" does not allow wrapping. Content
+ | that does not fit the block container overflows it.
+ |   https://www.w3.org/TR/css3-text/#white-space-property
+ -->
+<html>
+<head>
+  <meta charset="utf-8">
+  <style>
+    body {
+      margin: 0px;
+      font-family: Roboto;
+      font-size: 20px;
+    }
+    span {
+      white-space: nowrap;
+    }
+    .containing-block {
+      background-color: #03a9f4;
+      width: 200px;
+    }
+  </style>
+</head>
+<body>
+  <div class="containing-block">
+    <span>الحلقة النهائية من #MBCTheVoiceKids بتقنية الـ 360</span>
+  </div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/layout_tests.txt b/src/cobalt/layout_tests/testdata/css-text-3/layout_tests.txt
index a001297..f76855c 100644
--- a/src/cobalt/layout_tests/testdata/css-text-3/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/css-text-3/layout_tests.txt
@@ -1,4 +1,5 @@
 2-1-letters-should-all-appear-in-uppercase-with-text-transform-uppercase
+3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap
 3-br-elements-within-white-space-nowrap-block-should-generate-new-lines
 3-br-elements-within-white-space-pre-block-should-generate-new-lines
 3-br-elements-within-white-space-pre-line-block-should-generate-new-lines
diff --git a/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update-expected.png b/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update-expected.png
new file mode 100644
index 0000000..c3f8378
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update.html b/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update.html
new file mode 100644
index 0000000..de05b21
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/incremental-layout/child-being-moved-to-new-parent-should-trigger-inherited-style-update.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+ | When a child is moved from one parent to another it should update
+ | its inherited properties with the style of the new parent.
+ -->
+<html>
+<head>
+  <style>
+    body {
+      margin: 0px;
+      font-family: Roboto;
+      font-size: 18px;
+    }
+    #small-font {
+      font-size: 20px;
+      font-style: normal;
+    }
+    #large-font {
+      font-size: 40px;
+      font-style: italic;
+    }
+  </style>
+  <script>
+    if (window.testRunner) {
+      window.testRunner.waitUntilDone();
+    }
+
+    window.onload = function() {
+      if (window.testRunner) {
+        window.testRunner.DoNonMeasuredLayout();
+      }
+
+      var child = document.getElementById('child');
+      child.parentNode.removeChild(child);
+
+      var new_parent = document.getElementById('large-font');
+      new_parent.appendChild(child);
+
+      if (window.testRunner) {
+        window.testRunner.notifyDone();
+      }
+    }
+  </script>
+</head>
+<body>
+  <span id="small-font"><span id="child">TEST</span></span>
+  <span id="large-font"></span>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/incremental-layout/layout_tests.txt b/src/cobalt/layout_tests/testdata/incremental-layout/layout_tests.txt
index d6667ab..b74e440 100644
--- a/src/cobalt/layout_tests/testdata/incremental-layout/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/incremental-layout/layout_tests.txt
@@ -1,4 +1,5 @@
 added_inline_child_of_inline_box_gets_rendered
+child-being-moved-to-new-parent-should-trigger-inherited-style-update
 computed_style_change_gets_rendered
 cross_references_style_change_should_trigger_containing_block_update
 cross_references_style_change_should_trigger_stacking_context_update
diff --git a/src/cobalt/loader/about_fetcher.cc b/src/cobalt/loader/about_fetcher.cc
index 478c08e..81efad0 100644
--- a/src/cobalt/loader/about_fetcher.cc
+++ b/src/cobalt/loader/about_fetcher.cc
@@ -22,10 +22,15 @@
 namespace cobalt {
 namespace loader {
 
-AboutFetcher::AboutFetcher(Handler* handler) : Fetcher(handler) {
+AboutFetcher::AboutFetcher(Handler* handler)
+    : Fetcher(handler),
+      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
   MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&Handler::OnDone, base::Unretained(handler), this));
+      FROM_HERE,
+      base::Bind(&AboutFetcher::Fetch, weak_ptr_factory_.GetWeakPtr()));
 }
 
+void AboutFetcher::Fetch() { handler()->OnDone(this); }
+
 }  // namespace loader
 }  // namespace cobalt
diff --git a/src/cobalt/loader/about_fetcher.h b/src/cobalt/loader/about_fetcher.h
index deedfbd..606b7ef 100644
--- a/src/cobalt/loader/about_fetcher.h
+++ b/src/cobalt/loader/about_fetcher.h
@@ -19,6 +19,7 @@
 
 #if defined(ENABLE_ABOUT_SCHEME)
 
+#include "base/memory/weak_ptr.h"
 #include "cobalt/loader/fetcher.h"
 
 namespace cobalt {
@@ -29,6 +30,11 @@
 class AboutFetcher : public Fetcher {
  public:
   explicit AboutFetcher(Handler* handler);
+
+  void Fetch();
+
+ private:
+  base::WeakPtrFactory<AboutFetcher> weak_ptr_factory_;
 };
 
 }  // namespace loader
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.css b/src/cobalt/loader/embedded_resources/splash_screen.css
index c1400c9..0af40bf 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.css
+++ b/src/cobalt/loader/embedded_resources/splash_screen.css
@@ -1,5 +1,6 @@
 body {
   overflow: hidden;
+  font-size: 1.4815vh;  /* Corresponds to 16px at 1080p. */
 }
 
 #splash {
diff --git a/src/cobalt/media/fetcher_buffered_data_source.cc b/src/cobalt/media/fetcher_buffered_data_source.cc
index 3d96ea7..b50aabc 100644
--- a/src/cobalt/media/fetcher_buffered_data_source.cc
+++ b/src/cobalt/media/fetcher_buffered_data_source.cc
@@ -113,7 +113,6 @@
   DCHECK(message_loop_->BelongsToCurrentThread());
 
   base::AutoLock auto_lock(lock_);
-  DCHECK_EQ(fetcher_.get(), source);
   if (fetcher_.get() != source) {
     return;
   }
diff --git a/src/cobalt/renderer/backend/egl/graphics_context.cc b/src/cobalt/renderer/backend/egl/graphics_context.cc
index e62c053..a418417 100644
--- a/src/cobalt/renderer/backend/egl/graphics_context.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_context.cc
@@ -390,7 +390,6 @@
 void GraphicsContextEGL::SwapBuffers(RenderTargetEGL* surface) {
   TRACE_EVENT0("cobalt::renderer", "GraphicsContextEGL::SwapBuffers()");
 
-  GL_CALL(glFlush());
   EGL_CALL(eglSwapBuffers(display_, surface->GetSurface()));
 
   surface->increment_swap_count();
diff --git a/src/cobalt/renderer/backend/egl/graphics_system.cc b/src/cobalt/renderer/backend/egl/graphics_system.cc
index 4d615d5..16b5104 100644
--- a/src/cobalt/renderer/backend/egl/graphics_system.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_system.cc
@@ -16,6 +16,9 @@
 
 #include "cobalt/renderer/backend/egl/graphics_system.h"
 
+#if defined(ENABLE_GLIMP_TRACING)
+#include "base/debug/trace_event.h"
+#endif
 #if defined(GLES3_SUPPORTED)
 #include "cobalt/renderer/backend/egl/texture_data_pbo.h"
 #else
@@ -26,12 +29,34 @@
 #include "cobalt/renderer/backend/egl/graphics_context.h"
 #include "cobalt/renderer/backend/egl/texture.h"
 #include "cobalt/renderer/backend/egl/utils.h"
+#if defined(ENABLE_GLIMP_TRACING)
+#include "glimp/tracing/tracing.h"
+#endif
 
 namespace cobalt {
 namespace renderer {
 namespace backend {
 
+#if defined(ENABLE_GLIMP_TRACING)
+// Hookup glimp tracing to Chromium's base trace_event tracing.
+class GlimpToBaseTraceEventBridge : public glimp::TraceEventImpl {
+ public:
+  void BeginTrace(const char* name) OVERRIDE {
+    TRACE_EVENT_BEGIN0("glimp", name);
+  }
+  void EndTrace(const char* name) OVERRIDE { TRACE_EVENT_END0("glimp", name); }
+};
+
+GlimpToBaseTraceEventBridge s_glimp_to_base_trace_event_bridge;
+#endif  // #if defined(ENABLE_GLIMP_TRACING)
+
 GraphicsSystemEGL::GraphicsSystemEGL() {
+#if defined(ENABLE_GLIMP_TRACING)
+  // If glimp tracing is enabled, hook up glimp trace calls to Chromium's
+  // base trace_event calls.
+  glimp::SetTraceEventImplementation(&s_glimp_to_base_trace_event_bridge);
+#endif  // #if defined(ENABLE_GLIMP_TRACING)
+
   display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   CHECK_NE(EGL_NO_DISPLAY, display_);
   CHECK_EQ(EGL_SUCCESS, eglGetError());
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index 1a1fc84..2cb69c9 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -30,7 +30,6 @@
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/core/SkTypeface.h"
-#include "third_party/skia/include/ports/SkFontMgr.h"
 
 using cobalt::render_tree::Image;
 using cobalt::render_tree::ImageData;
@@ -45,6 +44,7 @@
     backend::GraphicsContextEGL* cobalt_context, GrContext* gr_context)
     : cobalt_context_(cobalt_context),
       gr_context_(gr_context),
+      font_manager_(SkFontMgr::RefDefault()),
       self_message_loop_(MessageLoop::current()) {}
 
 bool HardwareResourceProvider::PixelFormatSupported(
@@ -137,8 +137,8 @@
   TRACE_EVENT0("cobalt::renderer",
                "HardwareResourceProvider::HasLocalFontFamily()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkFontStyleSet> style_set(fm->matchFamily(font_family_name));
+  SkAutoTUnref<SkFontStyleSet> style_set(
+      font_manager_->matchFamily(font_family_name));
   return style_set->count() > 0;
 }
 
@@ -147,8 +147,7 @@
   TRACE_EVENT0("cobalt::renderer",
                "HardwareResourceProvider::GetLocalTypeface()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkTypeface> typeface(fm->matchFamilyStyle(
+  SkAutoTUnref<SkTypeface> typeface(font_manager_->matchFamilyStyle(
       font_family_name, CobaltFontStyleToSkFontStyle(font_style)));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
@@ -160,10 +159,9 @@
   TRACE_EVENT0("cobalt::renderer",
                "HardwareResourceProvider::GetCharacterFallbackTypeface()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkTypeface> typeface(
-      fm->matchFamilyStyleCharacter(0, CobaltFontStyleToSkFontStyle(font_style),
-                                    language.c_str(), character));
+  SkAutoTUnref<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
+      0, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
+      character));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
 
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
index aec9c85..5e01f73 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
@@ -24,6 +24,7 @@
 #include "cobalt/renderer/rasterizer/skia/hardware_image.h"
 #include "cobalt/renderer/rasterizer/skia/text_shaper.h"
 #include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/ports/SkFontMgr.h"
 
 namespace cobalt {
 namespace renderer {
@@ -89,6 +90,7 @@
   backend::GraphicsContextEGL* cobalt_context_;
   GrContext* gr_context_;
 
+  SkAutoTUnref<SkFontMgr> font_manager_;
   TextShaper text_shaper_;
 
   // We keep a handle to the message loop that this resource provider was
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
index 6c9c5f6..1f8996b 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -685,6 +685,12 @@
     const cobalt::render_tree::SolidColorBrush* solid_color_brush) {
   const cobalt::render_tree::ColorRGBA& color = solid_color_brush->color();
 
+  if (color.a() == 1.0f) {
+    paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
+  } else {
+    paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  }
+
   paint_->setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
                   color.b() * 255);
 }
@@ -695,8 +701,14 @@
 // methods will easily accept.
 struct SkiaColorStops {
   explicit SkiaColorStops(const render_tree::ColorStopList& color_stops)
-      : colors(color_stops.size()), positions(color_stops.size()) {
+      : colors(color_stops.size()),
+        positions(color_stops.size()),
+        has_alpha(false) {
     for (size_t i = 0; i < color_stops.size(); ++i) {
+      if (color_stops[i].color.a() < 1.0f) {
+        has_alpha = true;
+      }
+
       colors[i] = ToSkColor(color_stops[i].color);
       positions[i] = color_stops[i].position;
     }
@@ -704,6 +716,7 @@
 
   std::vector<SkColor> colors;
   std::vector<SkScalar> positions;
+  bool has_alpha;
 };
 
 }  // namespace
@@ -722,6 +735,12 @@
       linear_gradient_brush->color_stops().size(), SkShader::kClamp_TileMode,
       SkGradientShader::kInterpolateColorsInPremul_Flag, NULL));
   paint_->setShader(shader);
+
+  if (!skia_color_stops.has_alpha) {
+    paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
+  } else {
+    paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  }
 }
 
 void SkiaBrushVisitor::Visit(
@@ -751,6 +770,12 @@
       radial_gradient_brush->color_stops().size(), SkShader::kClamp_TileMode,
       SkGradientShader::kInterpolateColorsInPremul_Flag, &local_matrix));
   paint_->setShader(shader);
+
+  if (!skia_color_stops.has_alpha) {
+    paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
+  } else {
+    paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  }
 }
 
 void DrawRectWithBrush(SkCanvas* render_target,
@@ -820,6 +845,11 @@
     paint.setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
                   color.b() * 255);
     paint.setAntiAlias(anti_alias);
+    if (color.a() == 1.0f) {
+      paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    } else {
+      paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+    }
 
     SkPath path;
     path.addPoly(points, 4, true);
@@ -902,6 +932,11 @@
   const render_tree::ColorRGBA& color = border.top.color;
   paint.setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
                 color.b() * 255);
+  if (color.a() == 1.0f) {
+    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+  } else {
+    paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  }
 
   render_target->drawDRRect(
       RoundedRectToSkia(rect, rounded_corners),
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
index 409c787..f959c8b 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
@@ -73,6 +73,10 @@
   // state when re-using the sk_surface.
   canvas->save();
 
+  // Indicate that we do not care about the existing state of the canvas, which
+  // can allow for optimization on tile-based renderers.
+  canvas->discard();
+
   // Setup a clip rect on the sk_surface to the requested area.  This can save
   // us from drawing to pixels outside of the requested area, since the actual
   // sk_surface returned may be larger than the requested area.
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/config/SkUserConfig.h b/src/cobalt/renderer/rasterizer/skia/skia/config/SkUserConfig.h
index 5695744..078fff6 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/config/SkUserConfig.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/config/SkUserConfig.h
@@ -237,10 +237,18 @@
 
 // ===== End Cobalt-specific definitions =====
 
+// GrGLConfig.h settings customization for Cobalt.
+
 #if defined(STARBOARD)
 #if SB_HAS_QUIRK(GL_NO_CONSTANT_ATTRIBUTE_SUPPORT)
 #define GR_GL_NO_CONSTANT_ATTRIBUTES 1
 #endif // SB_HAS_QUIRK(GL_NO_CONSTANT_ATTRIBUTE_SUPPORT)
 #endif // defined(STARBOARD)
 
+// Avoid calling glGetError() after glTexImage, glBufferData,
+// glRenderbufferStorage, etc...  It can be potentially expensive to call on
+// some platforms, and Cobalt is designed for devices where we can ensure we
+// do not fail by running out of memory.
+#define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 0
+
 #endif  // SkUserConfig_DEFINED
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
index 93717ca..5be8703 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
+++ b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
@@ -17,13 +17,11 @@
 
   'sources': [
     'config/SkUserConfig.h',
-    'egl/src/gpu/cobalt/GrGpuFactory.cc',
     'src/effects/SkNV122RGBShader.cc',
     'src/effects/SkNV122RGBShader.h',
     'src/effects/SkYUV2RGBShader.cc',
     'src/effects/SkYUV2RGBShader.h',
     'src/google_logging.cc',
-    'src/gpu/gl/GrGLCreateNativeInterface_cobalt.cc',
     'src/ports/SkFontConfigParser_cobalt.cc',
     'src/ports/SkFontConfigParser_cobalt.h',
     'src/ports/SkFontMgr_cobalt.cc',
@@ -46,5 +44,11 @@
         'src/ports/SkMemory_starboard.cc',
       ],
     }],
+    ['gl_type != "none"', {
+      'sources': [
+        'egl/src/gpu/cobalt/GrGpuFactory.cc',
+        'src/gpu/gl/GrGLCreateNativeInterface_cobalt.cc',
+      ],
+    }],
   ],
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
index abe46c6..ee59b76 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -37,6 +37,9 @@
 namespace rasterizer {
 namespace skia {
 
+SoftwareResourceProvider::SoftwareResourceProvider()
+    : font_manager_(SkFontMgr::RefDefault()) {}
+
 bool SoftwareResourceProvider::PixelFormatSupported(
     render_tree::PixelFormat pixel_format) {
   return RenderTreeSurfaceFormatToSkia(pixel_format) == kN32_SkColorType;
@@ -99,8 +102,8 @@
   TRACE_EVENT0("cobalt::renderer",
                "SoftwareResourceProvider::HasLocalFontFamily()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkFontStyleSet> style_set(fm->matchFamily(font_family_name));
+  SkAutoTUnref<SkFontStyleSet> style_set(
+      font_manager_->matchFamily(font_family_name));
   return style_set->count() > 0;
 }
 
@@ -108,8 +111,7 @@
     const char* font_family_name, render_tree::FontStyle font_style) {
   TRACE_EVENT0("cobalt::renderer", "SoftwareResourceProvider::GetLocalFont()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkTypeface> typeface(fm->matchFamilyStyle(
+  SkAutoTUnref<SkTypeface> typeface(font_manager_->matchFamilyStyle(
       font_family_name, CobaltFontStyleToSkFontStyle(font_style)));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
@@ -121,10 +123,9 @@
   TRACE_EVENT0("cobalt::renderer",
                "SoftwareResourceProvider::GetCharacterFallbackTypeface()");
 
-  SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-  SkAutoTUnref<SkTypeface> typeface(
-      fm->matchFamilyStyleCharacter(0, CobaltFontStyleToSkFontStyle(font_style),
-                                    language.c_str(), character));
+  SkAutoTUnref<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
+      0, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
+      character));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
 
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
index 890f929..fd4419e 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
@@ -21,6 +21,7 @@
 
 #include "cobalt/render_tree/resource_provider.h"
 #include "cobalt/renderer/rasterizer/skia/text_shaper.h"
+#include "third_party/skia/include/ports/SkFontMgr.h"
 
 namespace cobalt {
 namespace renderer {
@@ -31,6 +32,8 @@
 // are to be consumed by this skia software rasterizer.
 class SoftwareResourceProvider : public render_tree::ResourceProvider {
  public:
+  SoftwareResourceProvider();
+
   bool PixelFormatSupported(render_tree::PixelFormat pixel_format) OVERRIDE;
   bool AlphaFormatSupported(render_tree::AlphaFormat alpha_format) OVERRIDE;
 
@@ -79,6 +82,7 @@
                      render_tree::FontVector* maybe_used_fonts) OVERRIDE;
 
  private:
+  SkAutoTUnref<SkFontMgr> font_manager_;
   TextShaper text_shaper_;
 };
 
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index 49f8313..23ec990 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -27,7 +27,12 @@
         'mozjs_property_enumerator.cc',
         'mozjs_source_code.cc',
         'proxy_handler.cc',
+        'referenced_object_map.cc',
         'util/exception_helpers.cc',
+        'weak_heap_object.cc',
+        'weak_heap_object.h',
+        'weak_heap_object_manager.cc',
+        'weak_heap_object_manager.h',
         'wrapper_factory.cc',
         'wrapper_private.cc',
       ],
@@ -40,7 +45,8 @@
         'defines': [
         # SpiderMonkey bindings implements indexed deleters.
         'ENGINE_SUPPORTS_INDEXED_DELETERS',
-        'ENGINE_SUPPORTS_INT64', ],
+        'ENGINE_SUPPORTS_INT64',
+        'ENGINE_SUPPORTS_STACK_TRACE_COLUMNS', ],
       },
       'conditions' :[
         ['cobalt_enable_jit == 1', {
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h b/src/cobalt/script/mozjs/mozjs_callback_function.h
index bcdf94e..2994166 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h
@@ -27,6 +27,7 @@
 #include "cobalt/script/callback_function.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
 #include "cobalt/script/mozjs/convert_callback_return_value.h"
+#include "cobalt/script/mozjs/weak_heap_object.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 
@@ -49,40 +50,44 @@
   typedef CallbackFunction<R()> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run()
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 0;
-
-    JSBool call_result = JS::Call(context_, this_value, function_, 0, NULL,
-        return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 0;
+
+      JSBool call_result = JS::Call(context_, this_value, function, 0, NULL,
+          return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1>
@@ -92,46 +97,50 @@
   typedef CallbackFunction<R(A1)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 1;
-
-    JS::Value args[1];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 1;
+
+      JS::Value args[1];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2>
@@ -141,48 +150,52 @@
   typedef CallbackFunction<R(A1, A2)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1,
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 2;
-
-    JS::Value args[2];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 2;
+
+      JS::Value args[2];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2, typename A3>
@@ -192,9 +205,9 @@
   typedef CallbackFunction<R(A1, A2, A3)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
@@ -202,40 +215,44 @@
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2,
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 3;
-
-    JS::Value args[3];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-    ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 3;
+
+      JS::Value args[3];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+      ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2, typename A3, typename A4>
@@ -245,9 +262,9 @@
   typedef CallbackFunction<R(A1, A2, A3, A4)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
@@ -256,41 +273,45 @@
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3,
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 4;
-
-    JS::Value args[4];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-    ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
-    ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 4;
+
+      JS::Value args[4];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+      ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
+      ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2, typename A3, typename A4,
@@ -301,9 +322,9 @@
   typedef CallbackFunction<R(A1, A2, A3, A4, A5)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
@@ -313,42 +334,46 @@
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4,
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 5;
-
-    JS::Value args[5];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-    ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
-    ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
-    ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 5;
+
+      JS::Value args[5];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+      ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
+      ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
+      ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2, typename A3, typename A4,
@@ -359,9 +384,9 @@
   typedef CallbackFunction<R(A1, A2, A3, A4, A5, A6)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
@@ -372,43 +397,47 @@
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5,
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 6;
-
-    JS::Value args[6];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-    ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
-    ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
-    ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
-    ToJSValue(context_, a6, auto_array_rooter.handleAt(5));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 6;
+
+      JS::Value args[6];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+      ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
+      ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
+      ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
+      ToJSValue(context_, a6, auto_array_rooter.handleAt(5));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename R, typename A1, typename A2, typename A3, typename A4,
@@ -419,9 +448,9 @@
   typedef CallbackFunction<R(A1, A2, A3, A4, A5, A6, A7)> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run(
@@ -433,44 +462,48 @@
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6,
       typename base::internal::CallbackParamTraits<A7>::ForwardType a7)
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
-
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = 7;
-
-    JS::Value args[7];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
-    ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
-    ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
-    ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
-    ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
-    ToJSValue(context_, a6, auto_array_rooter.handleAt(5));
-    ToJSValue(context_, a7, auto_array_rooter.handleAt(6));
-
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
-
+    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
+    if (function) {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
+
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other
+      // specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = 7;
+
+      JS::Value args[7];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      ToJSValue(context_, a1, auto_array_rooter.handleAt(0));
+      ToJSValue(context_, a2, auto_array_rooter.handleAt(1));
+      ToJSValue(context_, a3, auto_array_rooter.handleAt(2));
+      ToJSValue(context_, a4, auto_array_rooter.handleAt(3));
+      ToJSValue(context_, a5, auto_array_rooter.handleAt(4));
+      ToJSValue(context_, a6, auto_array_rooter.handleAt(5));
+      ToJSValue(context_, a7, auto_array_rooter.handleAt(6));
+
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 template <typename Signature>
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
index fb4e78e..6ea3efe 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
@@ -32,6 +32,7 @@
 #include "cobalt/script/callback_function.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
 #include "cobalt/script/mozjs/convert_callback_return_value.h"
+#include "cobalt/script/mozjs/weak_heap_object.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 
@@ -66,55 +67,60 @@
   typedef CallbackFunction<R($for ARG , [[A$(ARG)]])> BaseType;
 
   explicit MozjsCallbackFunction(JSContext* context, JS::HandleObject function)
-      : context_(context), function_(function) {
+      : context_(context), weak_function_(context, function) {
     DCHECK(context_);
-    DCHECK(JS_ObjectIsFunction(context_, function_));
+    DCHECK(JS_ObjectIsFunction(context_, function));
   }
 
   CallbackResult<R> Run($for ARG , [[
 
       typename base::internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]])
       const OVERRIDE {
-    JSAutoRequest auto_request(context_);
-    JSAutoCompartment auto_compartment(context_, function_);
+    CallbackResult<R> callback_result;
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
+      JSAutoRequest auto_request(context_);
+      JSAutoCompartment auto_compartment(context_, function);
 
-    // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
-    // Callback 'this' is set to null, unless overridden by other specifications
-    JS::Value this_value(JS::NullValue());
-    JS::RootedValue return_value(context_);
-    const int kNumArguments = $(ARITY);
+      // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
+      // Callback 'this' is set to null, unless overridden by other specifications
+      JS::Value this_value(JS::NullValue());
+      JS::RootedValue return_value(context_);
+      const int kNumArguments = $(ARITY);
 
 
 $if ARITY > 0 [[
-    JS::Value args[$(ARITY)];
-    js::SetValueRangeToNull(args, kNumArguments);
-    js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
-    $for ARG [[ToJSValue(context_, a$(ARG), auto_array_rooter.handleAt($(ARG - 1)));
-    ]]
+      JS::Value args[$(ARITY)];
+      js::SetValueRangeToNull(args, kNumArguments);
+      js::AutoValueArray auto_array_rooter(context_, args, kNumArguments);
+      $for ARG [[ToJSValue(context_, a$(ARG), auto_array_rooter.handleAt($(ARG - 1)));
+      ]]
 
-    JSBool call_result = JS::Call(context_, this_value, function_,
-        kNumArguments, args, return_value.address());
+      JSBool call_result = JS::Call(context_, this_value, function,
+          kNumArguments, args, return_value.address());
 ]] $else [[
-    JSBool call_result = JS::Call(context_, this_value, function_, 0, NULL,
-        return_value.address());
+      JSBool call_result = JS::Call(context_, this_value, function, 0, NULL,
+          return_value.address());
 ]]
 
-
-    CallbackResult<R> callback_result;
-    if (!call_result) {
-      DLOG(WARNING) << "Exception in callback.";
-      callback_result.exception = true;
-    } else {
-      callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      if (!call_result) {
+        DLOG(WARNING) << "Exception in callback.";
+        callback_result.exception = true;
+      } else {
+        callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
+      }
     }
     return callback_result;
   }
 
-  JSObject* handle() const { return function_; }
+  JSObject* handle() const { return weak_function_.Get(); }
 
  private:
   JSContext* context_;
-  mutable JS::Heap<JSObject*> function_;
+  WeakHeapObject weak_function_;
 };
 
 ]]
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index 5587773..23444fa 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -16,9 +16,10 @@
 
 #include "cobalt/script/mozjs/mozjs_engine.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
-
 #include "third_party/mozjs/js/src/jsapi.h"
 
 namespace cobalt {
@@ -36,12 +37,22 @@
       JS_NewRuntime(kGarbageCollectionThresholdBytes, JS_NO_HELPER_THREADS);
   CHECK(runtime_);
 
+  JS_SetRuntimePrivate(runtime_, this);
+
   // Use incremental garbage collection.
   JS_SetGCParameter(runtime_, JSGC_MODE, JSGC_MODE_INCREMENTAL);
+
   // Allow Spidermonkey to allocate as much memory as it needs. If this limit
   // is set we could limit the memory used by JS and "gracefully" restart,
   // for example.
   JS_SetGCParameter(runtime_, JSGC_MAX_BYTES, 0xffffffff);
+
+  // Callback to be called whenever a JSContext is created or destroyed for this
+  // JSRuntime.
+  JS_SetContextCallback(runtime_, &MozjsEngine::ContextCallback);
+
+  // Callback to be called during garbage collection during the sweep phase.
+  JS_SetFinalizeCallback(runtime_, &MozjsEngine::FinalizeCallback);
 }
 
 MozjsEngine::~MozjsEngine() {
@@ -61,10 +72,42 @@
 
 void MozjsEngine::ReportExtraMemoryCost(size_t bytes) { NOTIMPLEMENTED(); }
 
+JSBool MozjsEngine::ContextCallback(JSContext* context, unsigned context_op) {
+  JSRuntime* runtime = JS_GetRuntime(context);
+  MozjsEngine* engine =
+      static_cast<MozjsEngine*>(JS_GetRuntimePrivate(runtime));
+  DCHECK(engine->thread_checker_.CalledOnValidThread());
+  if (context_op == JSCONTEXT_NEW) {
+    engine->contexts_.push_back(context);
+  } else if (context_op == JSCONTEXT_DESTROY) {
+    ContextVector::iterator it =
+        std::find(engine->contexts_.begin(), engine->contexts_.end(), context);
+    if (it != engine->contexts_.end()) {
+      engine->contexts_.erase(it);
+    }
+  }
+  return true;
+}
+
+void MozjsEngine::FinalizeCallback(JSFreeOp* free_op, JSFinalizeStatus status,
+                                   JSBool is_compartment) {
+  MozjsEngine* engine =
+      static_cast<MozjsEngine*>(JS_GetRuntimePrivate(free_op->runtime()));
+  DCHECK(engine->thread_checker_.CalledOnValidThread());
+  if (status == JSFINALIZE_GROUP_START) {
+    for (int i = 0; i < engine->contexts_.size(); ++i) {
+      MozjsGlobalObjectProxy* global_environment =
+          MozjsGlobalObjectProxy::GetFromContext(engine->contexts_[i]);
+      global_environment->DoSweep();
+    }
+  }
+}
+
 }  // namespace mozjs
 
 scoped_ptr<JavaScriptEngine> JavaScriptEngine::CreateEngine() {
   return make_scoped_ptr<JavaScriptEngine>(new mozjs::MozjsEngine());
 }
+
 }  // namespace script
 }  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/mozjs_engine.h b/src/cobalt/script/mozjs/mozjs_engine.h
index bfed33e..12a24fd 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.h
+++ b/src/cobalt/script/mozjs/mozjs_engine.h
@@ -16,6 +16,8 @@
 #ifndef COBALT_SCRIPT_MOZJS_MOZJS_ENGINE_H_
 #define COBALT_SCRIPT_MOZJS_MOZJS_ENGINE_H_
 
+#include <vector>
+
 #include "base/threading/thread_checker.h"
 #include "cobalt/script/javascript_engine.h"
 #include "third_party/mozjs/js/src/jsapi.h"
@@ -34,11 +36,19 @@
   void ReportExtraMemoryCost(size_t bytes) OVERRIDE;
 
  private:
+  static JSBool ContextCallback(JSContext* context, unsigned context_op);
+  static void FinalizeCallback(JSFreeOp* free_op, JSFinalizeStatus status,
+                               JSBool is_compartment);
+
   base::ThreadChecker thread_checker_;
 
   // Top-level object that represents the Javascript engine. Typically there is
   // one per process, but it's allowed to have multiple.
   JSRuntime* runtime_;
+
+  // A list of all contexts created for this JSRuntime.
+  typedef std::vector<JSContext*> ContextVector;
+  ContextVector contexts_;
 };
 }  // namespace mozjs
 }  // namespace script
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
index 8622146..c56be2c 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
@@ -26,6 +26,7 @@
 #include "cobalt/script/mozjs/mozjs_source_code.h"
 #include "cobalt/script/mozjs/mozjs_wrapper_handle.h"
 #include "cobalt/script/mozjs/proxy_handler.h"
+#include "cobalt/script/mozjs/referenced_object_map.h"
 #include "cobalt/script/mozjs/util/exception_helpers.h"
 #include "third_party/mozjs/js/src/jsfriendapi.h"
 #include "third_party/mozjs/js/src/jsfun.h"
@@ -154,6 +155,7 @@
   JS_SetErrorReporter(context_, &MozjsGlobalObjectProxy::ReportErrorHandler);
 
   wrapper_factory_.reset(new WrapperFactory(context_));
+  referenced_objects_.reset(new ReferencedObjectMap(context_));
 
   JS_AddExtraGCRootsTracer(runtime, TraceFunction, this);
 }
@@ -268,6 +270,12 @@
   return NULL;
 }
 
+void MozjsGlobalObjectProxy::DoSweep() {
+  weak_object_manager_.SweepUnmarkedObjects();
+  // Remove NULL references after sweeping weak references.
+  referenced_objects_->RemoveNullReferences();
+}
+
 MozjsGlobalObjectProxy* MozjsGlobalObjectProxy::GetFromContext(
     JSContext* context) {
   MozjsGlobalObjectProxy* global_proxy =
@@ -336,9 +344,16 @@
            global_object_environment->cached_interface_data_.begin();
        it != global_object_environment->cached_interface_data_.end(); ++it) {
     InterfaceData* data = it->second;
-    JS_CallHeapObjectTracer(trace, &data->prototype, "MozjsGlobalObjectProxy");
-    JS_CallHeapObjectTracer(trace, &data->interface_object,
-                            "MozjsGlobalObjectProxy");
+    // Check whether prototype and interface object for this interface have been
+    // created yet or not before attempting to trace them.
+    if (data->prototype) {
+      JS_CallHeapObjectTracer(trace, &data->prototype,
+                              "MozjsGlobalObjectProxy");
+    }
+    if (data->interface_object) {
+      JS_CallHeapObjectTracer(trace, &data->interface_object,
+                              "MozjsGlobalObjectProxy");
+    }
   }
 }
 
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
index 0355d37..fc0b760 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
@@ -27,6 +27,7 @@
 #include "cobalt/script/global_object_proxy.h"
 #include "cobalt/script/mozjs/interface_data.h"
 #include "cobalt/script/mozjs/util/exception_helpers.h"
+#include "cobalt/script/mozjs/weak_heap_object_manager.h"
 #include "cobalt/script/mozjs/wrapper_factory.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jsproxy.h"
@@ -35,6 +36,9 @@
 namespace script {
 namespace mozjs {
 
+class ReferencedObjectMap;
+class WeakHandle;
+
 // Manages a handle to a JavaScript engine's global object. The lifetime of
 // the global object is not necessarily tied to the lifetime of the proxy.
 class MozjsGlobalObjectProxy : public GlobalObjectProxy,
@@ -86,6 +90,12 @@
 
   WrapperFactory* wrapper_factory() { return wrapper_factory_.get(); }
 
+  ReferencedObjectMap* referenced_objects() {
+    return referenced_objects_.get();
+  }
+
+  WeakHeapObjectManager* weak_object_manager() { return &weak_object_manager_; }
+
   // Used for CallWith=EnvironmentSettings
   void SetEnvironmentSettings(EnvironmentSettings* environment_settings) {
     DCHECK(!environment_settings_);
@@ -107,6 +117,11 @@
   void CacheInterfaceData(intptr_t key, InterfaceData* interface_data);
   InterfaceData* GetInterfaceData(intptr_t key);
 
+  // This will be called during garbage collection after GC objects have been
+  // marked, but before they have been finalized. This allows an opportunity to
+  // sweep away references to GC objects that will be deleted.
+  void DoSweep();
+
   static MozjsGlobalObjectProxy* GetFromContext(JSContext* context);
 
  protected:
@@ -132,6 +147,8 @@
 
   base::ThreadChecker thread_checker_;
   JSContext* context_;
+  WeakHeapObjectManager weak_object_manager_;
+  scoped_ptr<ReferencedObjectMap> referenced_objects_;
   CachedInterfaceData cached_interface_data_;
   STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
   ContextDestructor context_destructor_;
diff --git a/src/cobalt/script/mozjs/mozjs_object_handle.h b/src/cobalt/script/mozjs/mozjs_object_handle.h
index 6e59df8..e6c7827 100644
--- a/src/cobalt/script/mozjs/mozjs_object_handle.h
+++ b/src/cobalt/script/mozjs/mozjs_object_handle.h
@@ -19,6 +19,7 @@
 #include "base/optional.h"
 #include "cobalt/script/mozjs/mozjs_user_object_holder.h"
 #include "cobalt/script/mozjs/type_traits.h"
+#include "cobalt/script/mozjs/weak_heap_object.h"
 #include "cobalt/script/opaque_handle.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 
@@ -33,17 +34,14 @@
 class MozjsObjectHandle : public OpaqueHandle {
  public:
   typedef OpaqueHandle BaseType;
-  JSObject* handle() const { return handle_; }
+  JSObject* handle() const { return handle_.Get(); }
 
  private:
-  MozjsObjectHandle(JSContext*, JS::HandleObject object)
-      : handle_(object) {}
+  MozjsObjectHandle(JSContext* context, JS::HandleObject object)
+      : handle_(context, object) {}
   ~MozjsObjectHandle() {}
 
-  // Note that this class does not root this JS::Heap<> object. Rooting of this
-  // object is done in MozjsUserObjectHolder when ownership of a reference to
-  // this is registered.
-  JS::Heap<JSObject*> handle_;
+  WeakHeapObject handle_;
 
   friend class MozjsUserObjectHolder<MozjsObjectHandle>;
   friend class base::optional<MozjsObjectHandle>;
diff --git a/src/cobalt/script/mozjs/mozjs_user_object_holder.h b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
index de47435..e51a8bb 100644
--- a/src/cobalt/script/mozjs/mozjs_user_object_holder.h
+++ b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
@@ -19,6 +19,8 @@
 #include "base/hash_tables.h"
 #include "base/memory/weak_ptr.h"
 #include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include "cobalt/script/mozjs/referenced_object_map.h"
 #include "cobalt/script/mozjs/wrapper_factory.h"
 #include "cobalt/script/mozjs/wrapper_private.h"
 #include "cobalt/script/script_object.h"
@@ -50,22 +52,26 @@
 
   void RegisterOwner(Wrappable* owner) OVERRIDE {
     JS::RootedObject owned_object(context_, js_object());
-    WrapperPrivate* wrapper_private =
-        WrapperPrivate::GetFromWrappable(owner, context_, wrapper_factory_);
-    wrappable_and_private_hash_map_.insert(
-        std::make_pair(owner, wrapper_private->AsWeakPtr()));
-    wrapper_private->AddReferencedObject(owned_object);
+    DLOG_IF(WARNING, !owned_object)
+        << "Owned object has been garbage collected.";
+    if (owned_object) {
+      MozjsGlobalObjectProxy* global_environment =
+          MozjsGlobalObjectProxy::GetFromContext(context_);
+      intptr_t key = ReferencedObjectMap::GetKeyForWrappable(owner);
+      global_environment->referenced_objects()->AddReferencedObject(
+          key, owned_object);
+    }
   }
 
   void DeregisterOwner(Wrappable* owner) OVERRIDE {
+    // |owner| may be in the process of being destructed, so don't use it.
     JS::RootedObject owned_object(context_, js_object());
-    WrappableAndPrivateHashMap::iterator it =
-        wrappable_and_private_hash_map_.find(owner);
-    if (it != wrappable_and_private_hash_map_.end() && it->second) {
-      JS::RootedObject object_proxy(context_, it->second->js_object_proxy());
-      if (object_proxy) {
-        it->second->RemoveReferencedObject(owned_object);
-      }
+    if (owned_object) {
+      MozjsGlobalObjectProxy* global_environment =
+          MozjsGlobalObjectProxy::GetFromContext(context_);
+      intptr_t key = ReferencedObjectMap::GetKeyForWrappable(owner);
+      global_environment->referenced_objects()->RemoveReferencedObject(
+          key, owned_object);
     }
   }
 
@@ -104,7 +110,6 @@
   JSContext* context_;
   base::optional<MozjsUserObjectType> object_handle_;
   WrapperFactory* wrapper_factory_;
-  WrappableAndPrivateHashMap wrappable_and_private_hash_map_;
 };
 
 }  // namespace mozjs
diff --git a/src/cobalt/script/mozjs/referenced_object_map.cc b/src/cobalt/script/mozjs/referenced_object_map.cc
new file mode 100644
index 0000000..d356f62
--- /dev/null
+++ b/src/cobalt/script/mozjs/referenced_object_map.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/script/mozjs/referenced_object_map.h"
+
+#include <utility>
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+ReferencedObjectMap::ReferencedObjectMap(JSContext* context)
+    : context_(context) {}
+
+// Add/Remove a reference from a WrapperPrivate to a JSValue.
+void ReferencedObjectMap::AddReferencedObject(intptr_t key,
+                                              JS::HandleObject referee) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(referee);
+  referenced_objects_.insert(
+      std::make_pair(key, WeakHeapObject(context_, referee)));
+}
+
+void ReferencedObjectMap::RemoveReferencedObject(intptr_t key,
+                                                 JS::HandleObject referee) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  std::pair<ReferencedObjectMultiMap::iterator,
+            ReferencedObjectMultiMap::iterator> pair_range =
+      referenced_objects_.equal_range(key);
+  for (ReferencedObjectMultiMap::iterator it = pair_range.first;
+       it != pair_range.second; ++it) {
+    if (it->second.Get() == referee) {
+      // There may be multiple mappings between a specific owner and a JS
+      // object. Only remove the first mapping.
+      referenced_objects_.erase(it);
+      return;
+    }
+  }
+  DLOG(WARNING) << "No reference to the specified object found.";
+}
+
+void ReferencedObjectMap::TraceReferencedObjects(JSTracer* trace,
+                                                 intptr_t key) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  std::pair<ReferencedObjectMultiMap::iterator,
+            ReferencedObjectMultiMap::iterator> pair_range =
+      referenced_objects_.equal_range(key);
+  for (ReferencedObjectMultiMap::iterator it = pair_range.first;
+       it != pair_range.second; ++it) {
+    it->second.Trace(trace);
+  }
+}
+
+void ReferencedObjectMap::RemoveNullReferences() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  for (ReferencedObjectMultiMap::iterator it = referenced_objects_.begin();
+       it != referenced_objects_.end();
+       /*Incremented in the loop */) {
+    if (it->second.Get()) {
+      ++it;
+    } else {
+      ReferencedObjectMultiMap::iterator erase_iterator = it++;
+      referenced_objects_.erase(erase_iterator);
+    }
+  }
+}
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/referenced_object_map.h b/src/cobalt/script/mozjs/referenced_object_map.h
new file mode 100644
index 0000000..c1d4924
--- /dev/null
+++ b/src/cobalt/script/mozjs/referenced_object_map.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef COBALT_SCRIPT_MOZJS_REFERENCED_OBJECT_MAP_H_
+#define COBALT_SCRIPT_MOZJS_REFERENCED_OBJECT_MAP_H_
+
+#include "base/hash_tables.h"
+#include "base/threading/thread_checker.h"
+#include "cobalt/script/mozjs/weak_heap_object.h"
+#include "cobalt/script/wrappable.h"
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+// Maintains a set of JSObjects that are reachable from a given object. This
+// relationship is registered by mapping a key to a JSObject. The calling code
+// should ensure that a key uniquely identifies the entity that holds a
+// reference to the JSObjects.
+// During garbage collection, supply a key to TraceReferencedObjects to trace
+// all objects that are registered as being reachable from the object
+// represented by that key.
+class ReferencedObjectMap {
+ public:
+  explicit ReferencedObjectMap(JSContext* context);
+
+  // Reinterpret the pointer as an integer to be used as a key for tracking
+  // referenced objects.
+  static intptr_t GetKeyForWrappable(const Wrappable* wrappable) {
+    return reinterpret_cast<intptr_t>(wrappable);
+  }
+
+  void AddReferencedObject(intptr_t key, JS::HandleObject referee);
+  void RemoveReferencedObject(intptr_t key, JS::HandleObject referee);
+
+  // Trace all objects referenced from this WrapperPrivate*.
+  void TraceReferencedObjects(JSTracer* trace, intptr_t key);
+
+  // Remove any referenced objects that are NULL. It may be the case that a
+  // weak reference to an object was garbage collected, so remove it from the
+  // internal list.
+  void RemoveNullReferences();
+
+ private:
+  typedef base::hash_multimap<intptr_t, WeakHeapObject>
+      ReferencedObjectMultiMap;
+
+  base::ThreadChecker thread_checker_;
+  JSContext* context_;
+  ReferencedObjectMultiMap referenced_objects_;
+};
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
+
+#endif  // COBALT_SCRIPT_MOZJS_REFERENCED_OBJECT_MAP_H_
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.cc b/src/cobalt/script/mozjs/util/exception_helpers.cc
index 9ef7f2c..1c4b8ad 100644
--- a/src/cobalt/script/mozjs/util/exception_helpers.cc
+++ b/src/cobalt/script/mozjs/util/exception_helpers.cc
@@ -41,7 +41,7 @@
   for (int i = 0; i < max_frames; ++i) {
     StackFrame sf;
     sf.line_number = stack_trace[i].lineno;
-    sf.column_number = 0;
+    sf.column_number = stack_trace[i].columnno;
     sf.function_name = "global code";
     if (stack_trace[i].fun) {
       JS::RootedString rooted_string(context,
diff --git a/src/cobalt/script/mozjs/weak_heap_object.cc b/src/cobalt/script/mozjs/weak_heap_object.cc
new file mode 100644
index 0000000..6b719bb
--- /dev/null
+++ b/src/cobalt/script/mozjs/weak_heap_object.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/script/mozjs/weak_heap_object.h"
+
+#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+WeakHeapObject::WeakHeapObject(JSContext* context, JS::HandleObject handle) {
+  MozjsGlobalObjectProxy* global_environment =
+      MozjsGlobalObjectProxy::GetFromContext(context);
+  Initialize(global_environment->weak_object_manager(), handle);
+}
+
+WeakHeapObject::WeakHeapObject(const WeakHeapObject& other) {
+  Initialize(other.weak_object_manager_, other.heap_);
+}
+
+WeakHeapObject& WeakHeapObject::operator=(const WeakHeapObject& rhs) {
+  Initialize(rhs.weak_object_manager_, rhs.heap_);
+  return *this;
+}
+
+void WeakHeapObject::Trace(JSTracer* trace) {
+  if (heap_) {
+    JS_CallHeapObjectTracer(trace, &heap_, "WeakHeapObject::Trace");
+  }
+}
+
+WeakHeapObject::~WeakHeapObject() {
+  // It's safe to call StopTracking even if StartTracking wasn't called. the
+  // WeakObjectManager handles the case where it's not currently tracking the
+  // WeakHeapObject.
+  weak_object_manager_->StopTracking(this);
+}
+
+void WeakHeapObject::Initialize(WeakHeapObjectManager* weak_heap_object_manager,
+                                JSObject* object) {
+  weak_object_manager_ = weak_heap_object_manager;
+  heap_ = object;
+  // Don't bother registering if the pointer is already NULL.
+  if (heap_) {
+    weak_object_manager_->StartTracking(this);
+  }
+}
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/weak_heap_object.h b/src/cobalt/script/mozjs/weak_heap_object.h
new file mode 100644
index 0000000..4a9a5b6
--- /dev/null
+++ b/src/cobalt/script/mozjs/weak_heap_object.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_H_
+#define COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_H_
+
+#include "cobalt/script/mozjs/weak_heap_object_manager.h"
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+// This class implements a weak reference to a JSObject. The JSObject that an
+// instance of this class is created with may get garbage collected. In that
+// case, subsequent calls to WeakHeapObject::Get() will return a NULL pointer.
+class WeakHeapObject {
+ public:
+  WeakHeapObject(JSContext* context, JS::HandleObject handle);
+  WeakHeapObject(const WeakHeapObject& other);
+
+  WeakHeapObject& operator=(const WeakHeapObject& rhs);
+  JSObject* Get() const { return heap_; }
+  void Trace(JSTracer* trace);
+
+  ~WeakHeapObject();
+
+ private:
+  void Initialize(WeakHeapObjectManager* weak_heap_object_manager,
+                  JSObject* object);
+
+  WeakHeapObjectManager* weak_object_manager_;
+  JS::Heap<JSObject*> heap_;
+
+  friend class WeakHeapObjectManager;
+};
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
+
+#endif  // COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_H_
diff --git a/src/cobalt/script/mozjs/weak_heap_object_manager.cc b/src/cobalt/script/mozjs/weak_heap_object_manager.cc
new file mode 100644
index 0000000..8f72068
--- /dev/null
+++ b/src/cobalt/script/mozjs/weak_heap_object_manager.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/script/mozjs/weak_heap_object_manager.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "cobalt/script/mozjs/weak_heap_object.h"
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+void WeakHeapObjectManager::SweepUnmarkedObjects() {
+  for (WeakHeapObjects::iterator it = weak_objects_.begin();
+       it != weak_objects_.end();
+       /* Incremented in the loop */) {
+    if (MaybeSweep(*it)) {
+      WeakHeapObjects::iterator erase_iterator = it++;
+      weak_objects_.erase(erase_iterator);
+    } else {
+      ++it;
+    }
+  }
+}
+
+WeakHeapObjectManager::~WeakHeapObjectManager() {
+  // If this is not empty, that means that some WeakHeapObject may outlive this
+  // class.
+  DCHECK(weak_objects_.empty());
+}
+
+void WeakHeapObjectManager::StartTracking(WeakHeapObject* weak_object) {
+  std::pair<WeakHeapObjects::iterator, bool> pib =
+      weak_objects_.insert(weak_object);
+  DCHECK(pib.second) << "WeakHeapObject was already being tracked.";
+}
+
+void WeakHeapObjectManager::StopTracking(WeakHeapObject* weak_object) {
+  // The WeakHeapObject may have already been removed from the weak_objects_
+  // set during the sweep phase.
+  WeakHeapObjects::iterator it = weak_objects_.find(weak_object);
+  if (it != weak_objects_.end()) {
+    weak_objects_.erase(it);
+  }
+}
+
+bool WeakHeapObjectManager::MaybeSweep(WeakHeapObject* weak_object) {
+  if (weak_object->heap_ &&
+      JS_IsAboutToBeFinalized(weak_object->heap_.unsafeGet())) {
+    weak_object->heap_.set(NULL);
+  }
+  return weak_object->heap_ == NULL;
+}
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/weak_heap_object_manager.h b/src/cobalt/script/mozjs/weak_heap_object_manager.h
new file mode 100644
index 0000000..64e158b
--- /dev/null
+++ b/src/cobalt/script/mozjs/weak_heap_object_manager.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_MANAGER_H_
+#define COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_MANAGER_H_
+
+#include "base/hash_tables.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+
+class WeakHeapObject;
+
+// WeakHeapObjectManager holds a reference to all WeakHeapObject instances. The
+// SweepUnmarkedObjects function should be called during garbage collection
+// after the marking phase. The underlying JS::Heap<> handle for any unmarked
+// handles will be set to NULL.
+class WeakHeapObjectManager {
+ public:
+  // Iterates over all WeakHeapObjects and sets their JS::Heap<> handles to NULL
+  // if the objects to which they hold a reference are about to be finalized.
+  void SweepUnmarkedObjects();
+  ~WeakHeapObjectManager();
+
+ private:
+  void StartTracking(WeakHeapObject* weak_object);
+  void StopTracking(WeakHeapObject* weak_object);
+
+  // Returns true if the underlying pointer is NULL, which will be the case if
+  // the object has been swept.
+  bool MaybeSweep(WeakHeapObject* weak_object);
+
+  typedef base::hash_set<WeakHeapObject*> WeakHeapObjects;
+  WeakHeapObjects weak_objects_;
+
+  friend class WeakHeapObject;
+};
+
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
+
+#endif  // COBALT_SCRIPT_MOZJS_WEAK_HEAP_OBJECT_MANAGER_H_
diff --git a/src/cobalt/script/mozjs/wrapper_private.cc b/src/cobalt/script/mozjs/wrapper_private.cc
index e129678..9328993 100644
--- a/src/cobalt/script/mozjs/wrapper_private.cc
+++ b/src/cobalt/script/mozjs/wrapper_private.cc
@@ -16,6 +16,8 @@
 
 #include "cobalt/script/mozjs/wrapper_private.h"
 
+#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include "cobalt/script/mozjs/referenced_object_map.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jsproxy.h"
 
@@ -23,27 +25,13 @@
 namespace script {
 namespace mozjs {
 
-void WrapperPrivate::AddReferencedObject(JS::HandleObject referee) {
-  referenced_objects_.push_back(new JS::Heap<JSObject*>(referee));
-}
-
-void WrapperPrivate::RemoveReferencedObject(JS::HandleObject referee) {
-  for (ReferencedObjectVector::iterator it = referenced_objects_.begin();
-       it != referenced_objects_.end(); ++it) {
-    if ((**it) == referee) {
-      referenced_objects_.erase(it);
-      return;
-    }
-  }
-  NOTREACHED();
-}
-
 // static
 void WrapperPrivate::AddPrivateData(JSContext* context,
                                     JS::HandleObject wrapper_proxy,
                                     const scoped_refptr<Wrappable>& wrappable) {
   DCHECK(js::IsProxy(wrapper_proxy));
-  WrapperPrivate* private_data = new WrapperPrivate(wrappable, wrapper_proxy);
+  WrapperPrivate* private_data =
+      new WrapperPrivate(context, wrappable, wrapper_proxy);
   JS::RootedObject target_object(context,
                                  js::GetProxyTargetObject(wrapper_proxy));
   JS_SetPrivate(target_object, private_data);
@@ -101,18 +89,36 @@
 void WrapperPrivate::Trace(JSTracer* trace, JSObject* object) {
   WrapperPrivate* wrapper_private =
       reinterpret_cast<WrapperPrivate*>(JS_GetPrivate(object));
-  DCHECK(wrapper_private);
-  for (ReferencedObjectVector::iterator it =
-           wrapper_private->referenced_objects_.begin();
-       it != wrapper_private->referenced_objects_.end(); ++it) {
-    JS::Heap<JSObject*>* referenced_object = *it;
-    JS_CallHeapObjectTracer(trace, referenced_object, "WrapperPrivate::Trace");
+  // Verify that this trace function is called for the object (rather than the
+  // proxy object).
+  DCHECK(!js::IsProxy(object));
+
+  // The GC could run on this object before we've had a chance to set its
+  // private data, so we must handle the case where JS_GetPrivate returns NULL.
+  if (wrapper_private) {
+    // Verify that WrapperPrivate::wrapper_proxy_'s target object is this
+    // object.
+    DCHECK_EQ(object,
+              js::GetProxyTargetObject(wrapper_private->wrapper_proxy_));
+
+    // The wrapper's proxy object will keep the wrapper object alive, but the
+    // reverse is not true, so we must trace it explicitly.
+    JS_CallHeapObjectTracer(trace, &wrapper_private->wrapper_proxy_,
+                            "WrapperPrivate::Trace");
+
+    MozjsGlobalObjectProxy* global_environment =
+        MozjsGlobalObjectProxy::GetFromContext(wrapper_private->context_);
+    intptr_t key = ReferencedObjectMap::GetKeyForWrappable(
+        wrapper_private->wrappable_.get());
+    global_environment->referenced_objects()->TraceReferencedObjects(trace,
+                                                                     key);
   }
 }
 
-WrapperPrivate::WrapperPrivate(const scoped_refptr<Wrappable>& wrappable,
+WrapperPrivate::WrapperPrivate(JSContext* context,
+                               const scoped_refptr<Wrappable>& wrappable,
                                JS::HandleObject wrapper_proxy)
-    : wrappable_(wrappable), wrapper_proxy_(wrapper_proxy) {
+    : context_(context), wrappable_(wrappable), wrapper_proxy_(wrapper_proxy) {
   DCHECK(js::IsProxy(wrapper_proxy));
 }
 
diff --git a/src/cobalt/script/mozjs/wrapper_private.h b/src/cobalt/script/mozjs/wrapper_private.h
index e80ec75..aecb44d 100644
--- a/src/cobalt/script/mozjs/wrapper_private.h
+++ b/src/cobalt/script/mozjs/wrapper_private.h
@@ -75,14 +75,13 @@
   static void Trace(JSTracer* trace, JSObject* object);
 
  private:
-  typedef ScopedVector<JS::Heap<JSObject*> > ReferencedObjectVector;
-  WrapperPrivate(const scoped_refptr<Wrappable>& wrappable,
+  WrapperPrivate(JSContext* context, const scoped_refptr<Wrappable>& wrappable,
                  JS::HandleObject wrapper_proxy);
   ~WrapperPrivate();
 
+  JSContext* context_;
   scoped_refptr<Wrappable> wrappable_;
   JS::Heap<JSObject*> wrapper_proxy_;
-  ReferencedObjectVector referenced_objects_;
 };
 
 }  // namespace mozjs
diff --git a/src/cobalt/script/stack_frame.cc b/src/cobalt/script/stack_frame.cc
index 09de508..6e6e15d 100644
--- a/src/cobalt/script/stack_frame.cc
+++ b/src/cobalt/script/stack_frame.cc
@@ -31,6 +31,7 @@
     if (!stack_frames[i].source_url.empty()) {
       backtrace_stream << " @ " << stack_frames[i].source_url << ':'
                        << stack_frames[i].line_number;
+      backtrace_stream << ":" << stack_frames[i].column_number;
     }
   }
   return backtrace_stream.str();
diff --git a/src/cobalt/storage/storage_manager.cc b/src/cobalt/storage/storage_manager.cc
index 3f91fda..d7d2e9c 100644
--- a/src/cobalt/storage/storage_manager.cc
+++ b/src/cobalt/storage/storage_manager.cc
@@ -108,6 +108,30 @@
   DCHECK(ok);
 }
 
+const std::string& GetFirstValidDatabaseFile(
+    const std::vector<std::string>& filenames) {
+  // Caller must ensure at least one file exists.
+  DCHECK_GT(filenames.size(), size_t(0));
+
+  for (size_t i = 0; i < filenames.size(); ++i) {
+    sql::Connection connection;
+    bool is_opened = connection.Open(FilePath(filenames[i]));
+    if (!is_opened) {
+      continue;
+    }
+    int err = connection.ExecuteAndReturnErrorCode("pragma schema_version;");
+    if (err != SQLITE_OK) {
+      continue;
+    }
+    // File can be opened as a database.
+    return filenames[i];
+  }
+
+  // Caller must handle case where a valid database file cannot be found.
+  DLOG(WARNING) << "Cannot find valid database file in save data";
+  return filenames[0];
+}
+
 }  // namespace
 
 StorageManager::StorageManager(const Options& options)
@@ -253,11 +277,9 @@
     filenames.push_back(kDefaultSaveFile);
   }
 
-  // Not a limitation of the VFS- we just need to figure out how to handle
-  // the case where there are multiple files in here.
-  DCHECK_EQ(1, filenames.size());
-
-  const std::string& save_name = filenames[0];
+  // Legacy Steel save data may contain multiple files (e.g. db-journal as well
+  // as db), so use the first one that looks like a valid database file.
+  const std::string& save_name = GetFirstValidDatabaseFile(filenames);
   bool ok = connection_->Open(FilePath(save_name));
   DCHECK(ok);
 
diff --git a/src/glimp/glimp_settings.gypi b/src/glimp/glimp_settings.gypi
index af9bf97..7ea4b74 100644
--- a/src/glimp/glimp_settings.gypi
+++ b/src/glimp/glimp_settings.gypi
@@ -26,5 +26,7 @@
     # http://stackoverflow.com/questions/29601786/c-preprocessor-building-a-path-string
     'GLIMP_EGLPLATFORM_INCLUDE="../../<(target_arch)/eglplatform_public.h"',
     'GLIMP_KHRPLATFORM_INCLUDE="../../<(target_arch)/khrplatform_public.h"',
+    # Uncomment the define below to enable and use tracing inside glimp.
+    # 'ENABLE_GLIMP_TRACING',
 ],
 }
diff --git a/src/glimp/tracing/tracing.cc b/src/glimp/tracing/tracing.cc
index 5f6dfae..ddf3031 100644
--- a/src/glimp/tracing/tracing.cc
+++ b/src/glimp/tracing/tracing.cc
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <cstddef>
+
 #include "glimp/tracing/tracing.h"
 
-#if GLIMP_TRACING_ENABLED
+#if defined(ENABLE_GLIMP_TRACING)
 
 namespace glimp {
 
@@ -42,4 +44,4 @@
 
 }  // namespace glimp
 
-#endif  // #if GLIMP_TRACING_ENABLED
+#endif  // #if defined(ENABLE_GLIMP_TRACING)
diff --git a/src/glimp/tracing/tracing.gyp b/src/glimp/tracing/tracing.gyp
index 785a711..f2635bd 100644
--- a/src/glimp/tracing/tracing.gyp
+++ b/src/glimp/tracing/tracing.gyp
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 {
-  # When GLIMP_TRACING_ENABLED is defined to 1 in tracing.h, the many
+  # When ENABLE_GLIMP_TRACING is defined in glimp_settings.gypi, the many
   # implementation functions that are annotated with GLIMP_TRACE_EVENT0 calls
   # will activate and allow profiling and flow visualization within glimp.
   #
@@ -34,6 +34,9 @@
         'tracing.h',
         'tracing.cc',
       ],
+      'includes': [
+        '../glimp_settings.gypi',
+      ],
     },
   ],
 }
diff --git a/src/glimp/tracing/tracing.h b/src/glimp/tracing/tracing.h
index 5e3ce08..8471f40 100644
--- a/src/glimp/tracing/tracing.h
+++ b/src/glimp/tracing/tracing.h
@@ -17,15 +17,11 @@
 #ifndef GLIMP_TRACING_TRACING_H_
 #define GLIMP_TRACING_TRACING_H_
 
-#if !defined(GLIMP_TRACING_ENABLED)
-#define GLIMP_TRACING_ENABLED 0
-#endif
-
-#if !GLIMP_TRACING_ENABLED
+#if !defined(ENABLE_GLIMP_TRACING)
 
 #define GLIMP_TRACE_EVENT0(event)
 
-#else  // #if GLIMP_TRACING_ENABLED
+#else  // !defined(ENABLE_GLIMP_TRACING)
 
 #define GLIMP_TRACE_EVENT0(event) \
   glimp::ScopedTraceEvent profileScope##__LINE__(event)
@@ -56,6 +52,6 @@
 
 }  // namespace glimp
 
-#endif  // #if GLIMP_TRACING_ENABLED
+#endif  // !defined(ENABLE_GLIMP_TRACING)
 
 #endif  // GLIMP_TRACING_TRACING_H_
diff --git a/src/media/base/pipeline_impl.cc b/src/media/base/pipeline_impl.cc
index 3b3918e..6857cf6 100644
--- a/src/media/base/pipeline_impl.cc
+++ b/src/media/base/pipeline_impl.cc
@@ -407,7 +407,6 @@
 }
 
 void PipelineImpl::SetDuration(TimeDelta duration) {
-  DCHECK(IsRunning());
   media_log_->AddEvent(
       media_log_->CreateTimeEvent(
           MediaLogEvent::DURATION_SET, "duration", duration));
diff --git a/src/media/base/shell_audio_bus.cc b/src/media/base/shell_audio_bus.cc
index db3da54..86f4129 100644
--- a/src/media/base/shell_audio_bus.cc
+++ b/src/media/base/shell_audio_bus.cc
@@ -50,10 +50,8 @@
 
 }  // namespace
 
-ShellAudioBus::ShellAudioBus(size_t channels,
-                             size_t frames,
-                             SampleType sample_type,
-                             StorageType storage_type)
+ShellAudioBus::ShellAudioBus(size_t channels, size_t frames,
+                             SampleType sample_type, StorageType storage_type)
     : channels_(channels),
       frames_(frames),
       sample_type_(sample_type),
@@ -220,6 +218,44 @@
   }
 }
 
+template <ShellAudioBus::StorageType T>
+inline uint8* ShellAudioBus::GetSamplePtrForType(size_t channel,
+                                                 size_t frame) const {
+  DCHECK_LT(channel, channels_);
+  DCHECK_LT(frame, frames_);
+
+  if (T == kInterleaved) {
+    return channel_data_[0] + sizeof(float) * (channels_ * frame + channel);
+  } else if (T == kPlanar) {
+    return channel_data_[channel] + sizeof(float) * frame;
+  } else {
+    NOTREACHED();
+  }
+
+  return NULL;
+}
+
+template <ShellAudioBus::StorageType T>
+inline float ShellAudioBus::GetFloat32SampleForType(size_t channel,
+                                                    size_t frame) const {
+  return *reinterpret_cast<const float*>(
+      GetSamplePtrForType<T>(channel, frame));
+}
+
+template <ShellAudioBus::StorageType SourceStorageType,
+          ShellAudioBus::StorageType DestStorageType>
+void ShellAudioBus::MixForType(const ShellAudioBus& source) {
+  const size_t frames = std::min(frames_, source.frames_);
+
+  for (size_t channel = 0; channel < channels_; ++channel) {
+    for (size_t frame = 0; frame < frames; ++frame) {
+      *reinterpret_cast<float*>(
+          GetSamplePtrForType<DestStorageType>(channel, frame)) +=
+          source.GetFloat32SampleForType<SourceStorageType>(channel, frame);
+    }
+  }
+}
+
 void ShellAudioBus::Mix(const ShellAudioBus& source) {
   DCHECK_EQ(channels_, source.channels_);
   DCHECK_EQ(sample_type_, kFloat32);
@@ -230,12 +266,20 @@
     return;
   }
 
-  size_t frames = std::min(frames_, source.frames_);
-  for (size_t channel = 0; channel < channels_; ++channel) {
-    for (size_t frame = 0; frame < frames; ++frame) {
-      *reinterpret_cast<float*>(GetSamplePtr(channel, frame)) +=
-          source.GetFloat32Sample(channel, frame);
-    }
+  // Profiling has identified this area of code as hot, so instead of calling
+  // GetSamplePtr, which branches on storage_type_ each time it is called, we
+  // branch once before we loop and inline the branch of the function we want.
+  DCHECK_EQ(GetSampleSizeInBytes(), sizeof(float));
+  if (source.storage_type_ == kInterleaved && storage_type_ == kInterleaved) {
+    MixForType<kInterleaved, kInterleaved>(source);
+  } else if (source.storage_type_ == kInterleaved && storage_type_ == kPlanar) {
+    MixForType<kInterleaved, kPlanar>(source);
+  } else if (source.storage_type_ == kPlanar && storage_type_ == kInterleaved) {
+    MixForType<kPlanar, kInterleaved>(source);
+  } else if (source.storage_type_ == kPlanar && storage_type_ == kPlanar) {
+    MixForType<kPlanar, kPlanar>(source);
+  } else {
+    NOTREACHED();
   }
 }
 
diff --git a/src/media/base/shell_audio_bus.h b/src/media/base/shell_audio_bus.h
index 195ce7c..6c43f8c 100644
--- a/src/media/base/shell_audio_bus.h
+++ b/src/media/base/shell_audio_bus.h
@@ -50,9 +50,7 @@
 
   enum StorageType { kInterleaved, kPlanar };
 
-  ShellAudioBus(size_t channels,
-                size_t frames,
-                SampleType sample_type,
+  ShellAudioBus(size_t channels, size_t frames, SampleType sample_type,
                 StorageType storage_type);
   ShellAudioBus(size_t frames, const std::vector<float*>& samples);
   ShellAudioBus(size_t channels, size_t frames, float* samples);
@@ -111,6 +109,20 @@
   uint8* GetSamplePtr(size_t channel, size_t frame);
   const uint8* GetSamplePtr(size_t channel, size_t frame) const;
 
+  // The *ForType functions below are optimized versions that assume what
+  // storage type the bus is using.  They are meant to be called after checking
+  // what storage type the bus is once, and then performing a batch of
+  // operations, where it is known that the type will not change.
+  // Note: The bus must have storage type of kFloat32.
+  template <StorageType T>
+  inline uint8* GetSamplePtrForType(size_t channel, size_t frame) const;
+
+  template <StorageType T>
+  inline float GetFloat32SampleForType(size_t channel, size_t frame) const;
+
+  template <StorageType SourceStorageType, StorageType DestStorageType>
+  void MixForType(const ShellAudioBus& source);
+
   // Contiguous block of channel memory if the memory is owned by this object.
   scoped_ptr_malloc<uint8, base::ScopedPtrAlignedFree> data_;
 
diff --git a/src/media/filters/video_renderer_base.cc b/src/media/filters/video_renderer_base.cc
index 80d1f3d..de91f9f 100644
--- a/src/media/filters/video_renderer_base.cc
+++ b/src/media/filters/video_renderer_base.cc
@@ -65,6 +65,19 @@
 #endif  // defined(__LB_SHELL__) || defined(COBALT)
 }
 
+VideoRendererBase::~VideoRendererBase() {
+  base::AutoLock auto_lock(lock_);
+  DCHECK(state_ == kStopped || state_ == kUninitialized) << state_;
+  DCHECK_EQ(thread_, base::kNullThreadHandle);
+#if !defined(__LB_SHELL__FOR_RELEASE__)
+  ++videos_played_;
+  DLOG_IF(INFO, late_frames_ != 0) << "Finished playing back with "
+                                   << late_frames_ << " late frames.";
+  DLOG_IF(INFO, late_frames_ == 0)
+      << "Finished playing back with no late frame.";
+#endif  // !defined(__LB_SHELL__FOR_RELEASE__)
+}
+
 void VideoRendererBase::Play(const base::Closure& callback) {
 #if defined(__LB_SHELL__) || defined(COBALT)
   TRACE_EVENT0("media_stack", "VideoRendererBase::Play()");
@@ -154,7 +167,12 @@
     return;
   }
 
-  decoder_->Stop(callback);
+  if (decoder_) {
+    decoder_->Stop(callback);
+    return;
+  }
+
+  callback.Run();
 }
 
 void VideoRendererBase::StopDecoder(const base::Closure& callback) {
@@ -223,6 +241,7 @@
   error_cb_ = error_cb;
   get_time_cb_ = get_time_cb;
   get_duration_cb_ = get_duration_cb;
+  state_ = kInitializing;
 
   scoped_ptr<VideoDecoderSelector> decoder_selector(
       new VideoDecoderSelector(base::MessageLoopProxy::current(),
@@ -250,6 +269,8 @@
   if (state_ == kStopped)
     return;
 
+  DCHECK_EQ(state_, kInitializing);
+
   if (!selected_decoder) {
     state_ = kUninitialized;
     base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
@@ -308,9 +329,11 @@
     }
 #endif  // defined(__LB_SHELL__) || defined(COBALT)
     if (frames_dropped > 0) {
-      PipelineStatistics statistics;
-      statistics.video_frames_dropped = frames_dropped;
-      statistics_cb_.Run(statistics);
+      if (!statistics_cb_.is_null()) {
+        PipelineStatistics statistics;
+        statistics.video_frames_dropped = frames_dropped;
+        statistics_cb_.Run(statistics);
+      }
       frames_dropped = 0;
     }
 
@@ -545,18 +568,6 @@
   }
 }
 
-VideoRendererBase::~VideoRendererBase() {
-  base::AutoLock auto_lock(lock_);
-  DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
-#if !defined(__LB_SHELL__FOR_RELEASE__)
-  ++videos_played_;
-  DLOG_IF(INFO, late_frames_ != 0)
-      << "Finished playing back with " << late_frames_ << " late frames.";
-  DLOG_IF(INFO, late_frames_ == 0)
-      << "Finished playing back with no late frame.";
-#endif  // !defined(__LB_SHELL__FOR_RELEASE__)
-}
-
 void VideoRendererBase::FrameReady(
     VideoDecoder::Status status,
     const scoped_refptr<VideoFrame>& incoming_frame) {
@@ -771,6 +782,7 @@
       return;
 
     case kUninitialized:
+    case kInitializing:
     case kPrerolled:
     case kFlushingDecoder:
     case kFlushed:
@@ -827,22 +839,10 @@
 
 void VideoRendererBase::OnDecoderResetDone() {
   base::AutoLock auto_lock(lock_);
-  // The state_ can be kStopped if video playback is stopped when a seek is in
-  // progress.  The easist way to reproduce this is to repost to
-  // OnDecoderResetDone() here until state_ is kStopped and manually quit
-  // playing a video when the first seek is in progress.
-  // To keep running the function when state_ is kStopped is safe, because the
-  // flush_cb_ will be handled by SerialRunner::RunNextInSeries() which is
-  // posted on a weak pointer.  The SerialRunner should already be destroyed in
-  // Pipeline::DoStop() when pending_callbacks_ is overwritten.
-  // Note that this part has been properly handled in the upstream as the video
-  // renderer is owned by Pipeline and all related tasks are posted with a weak
-  // pointer of the video renderer.  When the Pipeline is stopped, it will
-  // destroy the video renderer and this callback will not be called.  So don't
-  // apply this change during rebase.
-  if (state_ != kStopped) {
-    DCHECK_EQ(kFlushingDecoder, state_);
-  }
+  if (state_ == kStopped)
+    return;
+
+  DCHECK_EQ(kFlushingDecoder, state_);
   DCHECK(!pending_read_);
 
   state_ = kFlushing;
diff --git a/src/media/filters/video_renderer_base.h b/src/media/filters/video_renderer_base.h
index af1fec4..f842f18 100644
--- a/src/media/filters/video_renderer_base.h
+++ b/src/media/filters/video_renderer_base.h
@@ -199,6 +199,8 @@
   //       [kUninitialized] -------> [kError]
   //              |
   //              | Initialize()
+  //        [kInitializing]
+  //              |
   //              V        All frames returned
   //   +------[kFlushed]<-----[kFlushing]<--- OnDecoderResetDone()
   //   |          | Preroll() or upon                  ^
@@ -221,6 +223,7 @@
   // Simple state tracking variable.
   enum State {
     kUninitialized,
+    kInitializing,
     kPrerolled,
     kPaused,
     kFlushingDecoder,
diff --git a/src/media/filters/video_renderer_base_unittest.cc b/src/media/filters/video_renderer_base_unittest.cc
index 5a47838..f252a2e 100644
--- a/src/media/filters/video_renderer_base_unittest.cc
+++ b/src/media/filters/video_renderer_base_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/debug/stack_trace.h"
 #include "base/message_loop.h"
 #include "base/stl_util.h"
 #include "base/stringprintf.h"
@@ -118,26 +119,26 @@
 
   void InitializeRenderer(PipelineStatus expected) {
     SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
+    WaitableMessageLoopEvent event;
+    CallInitialize(event.GetPipelineStatusCB());
+    event.RunAndWaitForStatus(expected);
+  }
+
+  void CallInitialize(const PipelineStatusCB& status_cb) {
     VideoRendererBase::VideoDecoderList decoders;
     decoders.push_back(decoder_);
-
-    WaitableMessageLoopEvent event;
     renderer_->Initialize(
-        demuxer_stream_,
-        decoders,
-        event.GetPipelineStatusCB(),
+        demuxer_stream_, decoders, status_cb,
         base::Bind(&MockStatisticsCB::OnStatistics,
                    base::Unretained(&statistics_cb_object_)),
         base::Bind(&VideoRendererBaseTest::OnTimeUpdate,
                    base::Unretained(this)),
         base::Bind(&VideoRendererBaseTest::OnNaturalSizeChanged,
                    base::Unretained(this)),
-        ended_event_.GetClosure(),
-        error_event_.GetPipelineStatusCB(),
+        ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
         base::Bind(&VideoRendererBaseTest::GetTime, base::Unretained(this)),
         base::Bind(&VideoRendererBaseTest::GetDuration,
                    base::Unretained(this)));
-    event.RunAndWaitForStatus(expected);
   }
 
   void Play() {
@@ -358,12 +359,44 @@
   DISALLOW_COPY_AND_ASSIGN(VideoRendererBaseTest);
 };
 
+TEST_F(VideoRendererBaseTest, DoNothing) {
+  // Test that creation and deletion doesn't depend on calls to Initialize()
+  // and/or Stop().
+}
+
+TEST_F(VideoRendererBaseTest, StopWithoutInitialize) {
+  Stop();
+}
+
 TEST_F(VideoRendererBaseTest, Initialize) {
   Initialize();
   EXPECT_EQ(0, GetCurrentTimestampInMs());
   Shutdown();
 }
 
+static void ExpectNotCalled(PipelineStatus) {
+  base::debug::StackTrace stack;
+  ADD_FAILURE() << "Expected callback not to be called\n" << stack.ToString();
+}
+
+TEST_F(VideoRendererBaseTest, StopWhileInitializing) {
+  EXPECT_CALL(*decoder_, Initialize(_, _, _))
+      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  CallInitialize(base::Bind(&ExpectNotCalled));
+  Stop();
+
+  // ~VideoRendererBase() will CHECK() if we left anything initialized.
+}
+
+TEST_F(VideoRendererBaseTest, StopWhileFlushing) {
+  Initialize();
+  Pause();
+  renderer_->Flush(base::Bind(&ExpectNotCalled, PIPELINE_OK));
+  Stop();
+
+  // ~VideoRendererBase() will CHECK() if we left anything initialized.
+}
+
 TEST_F(VideoRendererBaseTest, Play) {
   Initialize();
   Play();
diff --git a/src/media/mp4/mp4_stream_parser.cc b/src/media/mp4/mp4_stream_parser.cc
index a001872..dbbc07b 100644
--- a/src/media/mp4/mp4_stream_parser.cc
+++ b/src/media/mp4/mp4_stream_parser.cc
@@ -502,6 +502,10 @@
     StreamParserBuffer::CopyFrom(&frame_buf[0], frame_buf.size(),
                                  runs_->is_keyframe());
 #endif
+  if (!stream_buf) {
+    DLOG(WARNING) << "Failed to create StreamParserBuffer";
+    return false;
+  }
 
   if (decrypt_config)
     stream_buf->SetDecryptConfig(decrypt_config.Pass());
diff --git a/src/media/player/can_play_type.cc b/src/media/player/can_play_type.cc
index d3880ae..5dc1883 100644
--- a/src/media/player/can_play_type.cc
+++ b/src/media/player/can_play_type.cc
@@ -24,9 +24,32 @@
 #include "media/audio/shell_audio_streamer.h"
 #include "media/player/crypto/key_systems.h"
 #include "media/player/mime_util.h"
+#if defined(OS_STARBOARD)
+#include "starboard/media.h"
+#endif  // defined(OS_STARBOARD)
 
 namespace media {
 
+#if defined(OS_STARBOARD)
+
+std::string CanPlayType(const std::string& content_type,
+                        const std::string& key_system) {
+  SbMediaSupportType type =
+      SbMediaCanPlayMimeAndKeySystem(content_type.c_str(), key_system.c_str());
+  switch (type) {
+    case kSbMediaSupportTypeNotSupported:
+      return "";
+    case kSbMediaSupportTypeMaybe:
+      return "maybe";
+    case kSbMediaSupportTypeProbably:
+      return "probably";
+  }
+  NOTREACHED();
+  return "";
+}
+
+#else  // defined(OS_STARBOARD)
+
 namespace {
 
 bool ContainsAAC51(const std::vector<std::string>& codecs) {
@@ -154,4 +177,6 @@
   return kProbably;
 }
 
+#endif  // defined(OS_STARBOARD)
+
 }  // namespace media
diff --git a/src/media/webm/webm_cluster_parser.cc b/src/media/webm/webm_cluster_parser.cc
index 8ec2c3a..035963e 100644
--- a/src/media/webm/webm_cluster_parser.cc
+++ b/src/media/webm/webm_cluster_parser.cc
@@ -23,6 +23,80 @@
   return counter_block;
 }
 
+namespace {
+
+uint32 ReadInteger(const uint8* buf, int size) {
+  // Read in the big-endian integer.
+  uint32 value = 0;
+  for (int i = 0; i < size; ++i)
+    value = (value << 8) | buf[i];
+  return value;
+}
+
+bool ExtractSubsamples(const uint8* buf,
+                       size_t frame_data_size,
+                       size_t num_partitions,
+                       std::vector<SubsampleEntry>* subsample_entries) {
+  subsample_entries->clear();
+  uint32 clear_bytes = 0;
+  // Partition is the wall between alternating sections. Partition offsets are
+  // relative to the start of the actual frame data.
+  // Size of clear/cipher sections can be calculated from the difference between
+  // adjacent partition offsets.
+  // Here is an example with 4 partitions (5 sections):
+  //   "clear |1 cipher |2 clear |3 cipher |4 clear"
+  // With the first and the last implicit partition included:
+  //   "|0 clear |1 cipher |2 clear |3 cipher |4 clear |5"
+  //   where partition_offset_0 = 0, partition_offset_5 = frame_data_size
+  // There are three subsamples in the above example:
+  //   Subsample0.clear_bytes = partition_offset_1 - partition_offset_0
+  //   Subsample0.cypher_bytes = partition_offset_2 - partition_offset_1
+  //   ...
+  //   Subsample2.clear_bytes = partition_offset_5 - partition_offset_4
+  //   Subsample2.cypher_bytes = 0
+  uint32 partition_offset = 0;
+  for (size_t i = 0, offset = 0; i <= num_partitions; ++i) {
+    const uint32 prev_partition_offset = partition_offset;
+    partition_offset =
+        (i == num_partitions)
+            ? frame_data_size
+            : ReadInteger(buf + offset, kWebMEncryptedFramePartitionOffsetSize);
+    offset += kWebMEncryptedFramePartitionOffsetSize;
+    if (partition_offset < prev_partition_offset) {
+      DVLOG(1) << "Partition should not be decreasing " << prev_partition_offset
+               << " " << partition_offset;
+      return false;
+    }
+
+    uint32 cypher_bytes = 0;
+    bool new_subsample_entry = false;
+    // Alternating clear and cipher sections.
+    if ((i % 2) == 0) {
+      clear_bytes = partition_offset - prev_partition_offset;
+      // Generate a new subsample when finishing reading partition offsets.
+      new_subsample_entry = i == num_partitions;
+    } else {
+      cypher_bytes = partition_offset - prev_partition_offset;
+      // Generate a new subsample after seeing a cipher section.
+      new_subsample_entry = true;
+    }
+
+    if (new_subsample_entry) {
+      if (clear_bytes == 0 && cypher_bytes == 0) {
+        DVLOG(1) << "Not expecting >2 partitions with the same offsets.";
+        return false;
+      }
+      SubsampleEntry entry;
+      entry.clear_bytes = clear_bytes;
+      entry.cypher_bytes = cypher_bytes;
+      subsample_entries->push_back(entry);
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
 WebMClusterParser::WebMClusterParser(
     int64 timecode_scale, int audio_track_num, int video_track_num,
     const std::string& audio_encryption_key_id,
@@ -237,6 +311,11 @@
       StreamParserBuffer::CopyFrom(data, size, is_keyframe);
 #endif  // defined(__LB_SHELL__) || defined(COBALT)
 
+  if (!buffer) {
+    DLOG(WARNING) << "Failed to create StreamParserBuffer";
+    return false;
+  }
+
   // Every encrypted Block has a signal byte and IV prepended to it. Current
   // encrypted WebM request for comments specification is here
   // http://wiki.webmproject.org/encryption/webm-encryption-rfc
@@ -247,13 +326,14 @@
           << "Got a block from an encrypted stream with no data.";
       return false;
     }
-    uint8 signal_byte = data[0];
+    const uint8 signal_byte = data[0];
     int data_offset = sizeof(signal_byte);
 
     // Setting the DecryptConfig object of the buffer while leaving the
     // initialization vector empty will tell the decryptor that the frame is
     // unencrypted.
     std::string counter_block;
+    std::vector<SubsampleEntry> subsample_entries;
 
     if (signal_byte & kWebMFlagEncryptedFrame) {
       if (size < kWebMSignalByteSize + kWebMIvSize) {
@@ -263,26 +343,57 @@
       }
       counter_block = GenerateCounterBlock(data + data_offset, kWebMIvSize);
       data_offset += kWebMIvSize;
+
+      if (signal_byte & kWebMFlagEncryptedFramePartitioned) {
+        if (size < data_offset + kWebMEncryptedFrameNumPartitionsSize) {
+          DVLOG(1) << "Got a partitioned encrypted block with not enough data "
+                   << size;
+          return false;
+        }
+
+        const size_t num_partitions = data[data_offset];
+        if (num_partitions == 0) {
+          DVLOG(1) << "Got a partitioned encrypted block with 0 partitions.";
+          return false;
+        }
+        data_offset += kWebMEncryptedFrameNumPartitionsSize;
+        const uint8* partition_data_start = data + data_offset;
+        data_offset += kWebMEncryptedFramePartitionOffsetSize * num_partitions;
+        if (size <= data_offset) {
+          DVLOG(1) << "Got a partitioned encrypted block with "
+                   << num_partitions << " partitions but not enough data "
+                   << size;
+          return false;
+        }
+        const size_t frame_data_size = size - data_offset;
+        if (!ExtractSubsamples(partition_data_start, frame_data_size,
+                               num_partitions, &subsample_entries)) {
+          return false;
+        }
+      }
     }
 
 #if defined(__LB_SHELL__) || defined(COBALT)
     // Don't copy prepended meta data as it is not used by the decrytor and
     // decoder.
-    buffer = StreamParserBuffer::CopyFrom(data + data_offset,

+    buffer = StreamParserBuffer::CopyFrom(data + data_offset,
                                           size - data_offset, is_keyframe);
 #endif  // defined(__LB_SHELL__) || defined(COBALT)
+    if (!buffer) {
+      DLOG(WARNING) << "Failed to create StreamParserBuffer";
+      return false;
+    }
 
     // TODO(fgalligan): Revisit if DecryptConfig needs to be set on unencrypted
     // frames after the CDM API is finalized.
     // Unencrypted frames of potentially encrypted streams currently set
     // DecryptConfig.
-    buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
-        encryption_key_id,
-        counter_block,
+    buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(
+        new DecryptConfig(encryption_key_id, counter_block,
 #if !defined(__LB_SHELL__) && !defined(COBALT)
-        data_offset,
+                          data_offset,
 #endif  // !defined(__LB_SHELL__) && !defined(COBALT)
-        std::vector<SubsampleEntry>())));
+                          subsample_entries)));
   }
 
   buffer->SetTimestamp(timestamp);
diff --git a/src/media/webm/webm_constants.h b/src/media/webm/webm_constants.h
index 150134b..c4150ad 100644
--- a/src/media/webm/webm_constants.h
+++ b/src/media/webm/webm_constants.h
@@ -203,8 +203,11 @@
 // Current encrypted WebM request for comments specification is here
 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
 const uint8 kWebMFlagEncryptedFrame = 0x1;
+const uint8 kWebMFlagEncryptedFramePartitioned = 0x2;
 const int kWebMIvSize = 8;
 const int kWebMSignalByteSize = 1;
+const int kWebMEncryptedFrameNumPartitionsSize = 1;
+const int kWebMEncryptedFramePartitionOffsetSize = 4;
 
 }  // namespace media
 
diff --git a/src/starboard/client_porting/README.md b/src/starboard/client_porting/README.md
index f07658e..75c8435 100644
--- a/src/starboard/client_porting/README.md
+++ b/src/starboard/client_porting/README.md
@@ -22,6 +22,13 @@
 files, not headers, so that the preprocessor replacements don't spread
 uncontrollably.
 
+For each `poem`, we try to name files in a consistent, formulaic manner.  With
+this scheme, we can easily determine the correct poem header while porting.
+This can also come handy if one were to write a script to assist in porting
+third party libraries.  In theory, the script would just look for includes
+in .cc files, where we have available poems and then wrap unprotected includes
+in #if !defined(STARBOARD), and include the poems if STARBOARD is defined.
+
 
 # "eztime" - Easy Time Functions
 
@@ -35,3 +42,4 @@
 `starboard/client_porting/eztime/eztime.h`, or you can include
 `starboard/client_porting/poem/eztime_poem.h` in your implementation file to
 automatically simulate POSIXy time functions.
+
diff --git a/src/starboard/client_porting/poem/abs_tests.cc b/src/starboard/client_porting/poem/abs_tests.cc
new file mode 100644
index 0000000..cfcc8c1
--- /dev/null
+++ b/src/starboard/client_porting/poem/abs_tests.cc
@@ -0,0 +1,47 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Test basic functionality of abs()
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifndef POEM_FULL_EMULATION
+#define POEM_FULL_EMULATION (1)
+#include "starboard/client_porting/poem/stdlib_poem.h"
+#endif
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(AbsTest, Positive) {
+  EXPECT_EQ(3, abs(3));
+}
+
+TEST(AbsTest, Zero) {
+  EXPECT_EQ(0, abs(0));
+}
+
+TEST(AbsTest, Negative) {
+  EXPECT_EQ(3, abs(-3));
+}
+
+TEST(AbsTest, FloatPositive) {
+  // this converts/truncates argument 3.41223 to 3, and then passes into abs
+  EXPECT_EQ(3, abs(3.41223));
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/src/starboard/client_porting/poem/eztime_poem.h b/src/starboard/client_porting/poem/eztime_poem.h
index 336f577..280b0c6 100644
--- a/src/starboard/client_porting/poem/eztime_poem.h
+++ b/src/starboard/client_porting/poem/eztime_poem.h
@@ -18,6 +18,8 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
 
+// #if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
 #include "starboard/client_porting/eztime/eztime.h"
 
 #undef time_t
@@ -37,4 +39,6 @@
 #define timegm(x) EzTimeTImplodeUTC(x)
 #define timelocal(x) EzTimeTImplodeLocal(x)
 
+// #endif // POEM_FULL_EMULATION
+
 #endif  // STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
diff --git a/src/starboard/client_porting/poem/include_all.c b/src/starboard/client_porting/poem/include_all.c
new file mode 100644
index 0000000..d5be96e
--- /dev/null
+++ b/src/starboard/client_porting/poem/include_all.c
@@ -0,0 +1,23 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Includes all headers in a C context to make sure they compile as C files.
+
+#include "eztime_poem.h"
+#include "stdio_poem.h"
+#include "stdlib_poem.h"
+#include "string_poem.h"
+#include "strings_poem.h"
+#include "wchar_poem.h"
+
diff --git a/src/starboard/client_porting/poem/main.cc b/src/starboard/client_porting/poem/main.cc
new file mode 100644
index 0000000..de25a95
--- /dev/null
+++ b/src/starboard/client_porting/poem/main.cc
@@ -0,0 +1,26 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/event.h"
+#include "starboard/system.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+void SbEventHandle(const SbEvent* event) {
+  if (event->type == kSbEventTypeStart) {
+    SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
+    ::testing::InitGoogleTest(&data->argument_count, data->argument_values);
+    int result = RUN_ALL_TESTS();
+    SbSystemRequestStop(result);
+  }
+}
diff --git a/src/starboard/client_porting/poem/poem.gyp b/src/starboard/client_porting/poem/poem.gyp
index 52233ef..afde08e 100644
--- a/src/starboard/client_porting/poem/poem.gyp
+++ b/src/starboard/client_porting/poem/poem.gyp
@@ -19,11 +19,29 @@
       'type': 'static_library',
       'sources': [
         'eztime_poem.h',
+        'stdio_poem.h',
+        'stdlib_poem.h',
+        'string_poem.h',
+        'strings_poem.h',
+        'wchar_poem.h',
       ],
       'dependencies': [
         '<(DEPTH)/starboard/client_porting/eztime/eztime.gyp:eztime',
         '<(DEPTH)/starboard/starboard.gyp:starboard',
       ],
     },
+    {
+      'target_name': 'poem_unittests',
+      'type': '<(gtest_target_type)',
+      'sources': [
+        'abs_tests.cc',
+        'include_all.c',
+        'main.cc',
+      ],
+      'dependencies': [
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+        '<(DEPTH)/starboard/starboard.gyp:starboard',
+      ],
+    },
   ],
 }
diff --git a/src/starboard/client_porting/poem/stdio_poem.h b/src/starboard/client_porting/poem/stdio_poem.h
new file mode 100644
index 0000000..761dff1
--- /dev/null
+++ b/src/starboard/client_porting/poem/stdio_poem.h
@@ -0,0 +1,37 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions in stdio.h
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
+
+#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
+#include "starboard/string.h"
+
+#define wcsncmp(s1, s2, c) SbStringCompareWide(s1, s2, c)
+
+// the following functions can have variable number of arguments
+// and, out of compatibility concerns, we chose to not use
+// __VA_ARGS__ functionality.
+#define vsnprintf SbStringFormat
+#define snprintf SbStringFormatF
+#define sprintf SbStringFormatUnsafeF
+#define vsscanf SbStringScan
+#define sscanf SbStringScanF
+
+#endif  // POEM_FULL_EMULATION
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
diff --git a/src/starboard/client_porting/poem/stdlib_poem.h b/src/starboard/client_porting/poem/stdlib_poem.h
new file mode 100644
index 0000000..54c028b
--- /dev/null
+++ b/src/starboard/client_porting/poem/stdlib_poem.h
@@ -0,0 +1,48 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions in stdlib.h
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
+
+#include "starboard/configuration.h"
+
+SB_C_INLINE int PoemAbs(int x) {
+  if (x < 0)
+    return -x;
+  return x;
+}
+
+#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
+#include "starboard/string.h"
+#include "starboard/system.h"
+
+// number conversion functions
+#define strtol(s, o, b) SbStringParseSignedInteger(s, o, b)
+#define atoi(v) SbStringAToI(v)
+#define atol(v) SbStringAToL(v)
+#define strtol(s, o, b) SbStringParseSignedInteger(s, o, b)
+#define strtoul(s, o, b) SbStringParseUnsignedInteger(s, o, b)
+#define strtoull(s, o, b) SbStringParseUInt64(s, o, b)
+#define strtod(s, o) SbStringParseDouble(s, o)
+
+#define qsort(b, ec, ew, c) SbSystemSort(b, ec, ew, c);
+
+#define abs(x) PoemAbs(x)
+
+#endif  // POEM_FULL_EMULATION
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
diff --git a/src/starboard/client_porting/poem/string_poem.h b/src/starboard/client_porting/poem/string_poem.h
new file mode 100644
index 0000000..93cbcd2
--- /dev/null
+++ b/src/starboard/client_porting/poem/string_poem.h
@@ -0,0 +1,119 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions in string.h
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
+
+#include "starboard/string.h"
+
+#ifdef __cplusplus
+// Finds the last occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr, C++ signature
+inline char* PoemFindLastCharacter(char* str, int character) {
+  const char* const_str = static_cast<const char*>(str);
+  const char c = static_cast<char>(character);
+  return const_cast<char*>(SbStringFindLastCharacter(const_str, c));
+}
+
+// Finds the last occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr, C++ signature
+inline const char* PoemFindLastCharacter(const char* str, int character) {
+  const char c = static_cast<char>(character);
+  return SbStringFindLastCharacter(str, c);
+}
+
+// Finds the first occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr
+inline char* PoemFindCharacter(char* str, int character) {
+  const char* const_str = static_cast<const char*>(str);
+  const char c = static_cast<char>(character);
+  return const_cast<char*>(SbStringFindCharacter(const_str, c));
+}
+
+// Finds the first occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr
+inline const char* PoemFindCharacter(const char* str, int character) {
+  const char c = static_cast<char>(character);
+  return SbStringFindCharacter(str, c);
+}
+
+#else
+
+// Finds the first occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr
+SB_C_INLINE char* PoemFindCharacter(const char* str, int character) {
+  // C-style cast used for C code
+  return (char*)(SbStringFindCharacter(str, character));
+}
+
+// Finds the last occurrence of |character| in |str|, returning a pointer to
+// the found character in the given string, or NULL if not found.
+// Meant to be a drop-in replacement for strchr
+SB_C_INLINE char* PoemFindLastCharacter(const char* str, int character) {
+  // C-style cast used for C code
+  return (char*)(SbStringFindLastCharacter(str, character));
+}
+#endif
+
+// Concatenates |source| onto the end of |out_destination|, presuming it has
+// |destination_size| total characters of storage available. Returns
+// |out_destination|.  This method is a drop-in replacement for strncat
+SB_C_INLINE char* PoemConcat(char* out_destination,
+                             const char* source,
+                             int destination_size) {
+  SbStringConcat(out_destination, source, destination_size);
+  return out_destination;
+}
+
+// Inline wrapper for an unsafe PoemConcat that assumes |out_destination| is
+// big enough. Returns |out_destination|.  Meant to be a drop-in replacement for
+// strcat.
+static SB_C_INLINE char* PoemConcatUnsafe(char* out_destination,
+                                          const char* source) {
+  return PoemConcat(out_destination, source, INT_MAX);
+}
+
+#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
+#define strlen(s) SbStringGetLength(s)
+#define strcpy(o, s) SbStringCopyUnsafe(dst, src)
+#define strncpy(o, s, ds) SbStringCopy(o, s, ds)
+#define strcat(o, s) PoemConcatUnsafe(o, s)
+#define strncat(o, s, ds) PoemConcat(o, s, ds)
+#define strdup(s) SbStringDuplicate(s)
+#define strchr(s, c) PoemFindCharacter(s, c)
+#define strrchr(s, c) PoemFindLastCharacter(s, c)
+#define strstr(s, c) SbStringFindString(s, c)
+#define strncmp(s1, s2, c) SbStringCompare(s1, s2, c)
+#define strcmp(s1, s2) SbStringCompareAll(s1, s2)
+
+// number conversion functions
+#define strtol(s, o, b) SbStringParseSignedInteger(s, o, b)
+#define atoi(v) SbStringAToI(v)
+#define atol(v) SbStringAToL(v)
+#define strtol(s, o, b) SbStringParseSignedInteger(s, o, b)
+#define strtoul(s, o, b) SbStringParseUnsignedInteger(s, o, b)
+#define strtoull(s, o, b) SbStringParseUInt64(s, o, b)
+#define strtod(s, o) SbStringParseDouble(s, o)
+
+#endif  // POEM_FULL_EMULATION
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
diff --git a/src/starboard/client_porting/poem/strings_poem.h b/src/starboard/client_porting/poem/strings_poem.h
new file mode 100644
index 0000000..9c77d36
--- /dev/null
+++ b/src/starboard/client_porting/poem/strings_poem.h
@@ -0,0 +1,29 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions in strings.h
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
+
+#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
+#include "starboard/string.h"
+
+#define strcasecmp(s1, s2) SbStringCompareNoCase(s1, s2)
+#define strncasecmp(s1, s2) SbStringCompareNoCaseN(s1, s2)
+
+#endif  // POEM_FULL_EMULATION
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
diff --git a/src/starboard/client_porting/poem/wchar_poem.h b/src/starboard/client_porting/poem/wchar_poem.h
new file mode 100644
index 0000000..c72ec8d
--- /dev/null
+++ b/src/starboard/client_porting/poem/wchar_poem.h
@@ -0,0 +1,29 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions in wchar.h
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
+
+#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+
+#include "starboard/string.h"
+
+#define vswprintf SbStringFormatWide
+#define wcsncmp(s1, s2, c) SbStringCompareWide(s1, s2, c)
+
+#endif  // POEM_FULL_EMULATION
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gyp b/src/starboard/linux/x64directfb/starboard_platform.gyp
index e692647..bea20b6 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gyp
+++ b/src/starboard/linux/x64directfb/starboard_platform.gyp
@@ -119,6 +119,7 @@
         '<(DEPTH)/starboard/shared/iso/string_find_string.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_double.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_signed_integer.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_uint64.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_unsigned_integer.cc',
@@ -232,7 +233,7 @@
         '<(DEPTH)/starboard/shared/pthread/thread_join.cc',
         '<(DEPTH)/starboard/shared/pthread/thread_set_local_value.cc',
         '<(DEPTH)/starboard/shared/pthread/thread_yield.cc',
-        '<(DEPTH)/starboard/shared/signal/crash_signals.cc',
+        '<(DEPTH)/starboard/shared/signal/crash_signals_sigaction.cc',
         '<(DEPTH)/starboard/shared/signal/crash_signals.h',
         '<(DEPTH)/starboard/shared/starboard/application.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_create.cc',
@@ -257,8 +258,11 @@
         '<(DEPTH)/starboard/shared/starboard/log_message.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_dump_stack.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
         '<(DEPTH)/starboard/shared/starboard/new.cc',
         '<(DEPTH)/starboard/shared/starboard/player/audio_decoder_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/audio_renderer_internal.cc',
diff --git a/src/starboard/linux/x64x11/starboard_platform.gyp b/src/starboard/linux/x64x11/starboard_platform.gyp
index 1609af2..3200d13 100644
--- a/src/starboard/linux/x64x11/starboard_platform.gyp
+++ b/src/starboard/linux/x64x11/starboard_platform.gyp
@@ -82,6 +82,7 @@
         '<(DEPTH)/starboard/shared/iso/string_find_string.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_double.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_signed_integer.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_uint64.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_unsigned_integer.cc',
@@ -195,7 +196,7 @@
         '<(DEPTH)/starboard/shared/pthread/thread_join.cc',
         '<(DEPTH)/starboard/shared/pthread/thread_set_local_value.cc',
         '<(DEPTH)/starboard/shared/pthread/thread_yield.cc',
-        '<(DEPTH)/starboard/shared/signal/crash_signals.cc',
+        '<(DEPTH)/starboard/shared/signal/crash_signals_sigaction.cc',
         '<(DEPTH)/starboard/shared/signal/crash_signals.h',
         '<(DEPTH)/starboard/shared/starboard/application.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_create.cc',
@@ -218,8 +219,11 @@
         '<(DEPTH)/starboard/shared/starboard/log_message.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_dump_stack.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
         '<(DEPTH)/starboard/shared/starboard/new.cc',
         '<(DEPTH)/starboard/shared/starboard/player/audio_decoder_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/audio_renderer_internal.cc',
diff --git a/src/starboard/media.h b/src/starboard/media.h
index e3dc6d6..89f2608 100644
--- a/src/starboard/media.h
+++ b/src/starboard/media.h
@@ -63,6 +63,20 @@
   kSbMediaAudioCodecVorbis,
 } SbMediaAudioCodec;
 
+// Types of media support which is a direct map as the result of canPlayType()
+// specified in the following link:
+// https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype
+typedef enum SbMediaSupportType {
+  // The media type cannot be played.
+  kSbMediaSupportTypeNotSupported,
+
+  // Cannot determinate if the media type is playable without playing it.
+  kSbMediaSupportTypeMaybe,
+
+  // The media type seems to be playable.
+  kSbMediaSupportTypeProbably,
+} SbMediaSupportType;
+
 // Possible audio connector types.
 typedef enum SbMediaAudioConnector {
   kSbMediaAudioConnectorNone,
@@ -223,6 +237,22 @@
 SB_EXPORT bool SbMediaIsAudioSupported(SbMediaVideoCodec audio_codec,
                                        int64_t bitrate);
 
+// Returns information on whether the playback of the specific media described
+// by |mime| and encrypted using |key_system| can be played.
+// |mime| contains the mime information of the media in the form of 'video/webm'
+// or 'video/mp4; codecs="avc1.42001E"'.  It may include arbitrary parameters
+// like "codecs", "channels", etc..
+// |key_system| should be a lower case in fhe form of
+// "com.example.somesystem" as suggested by
+// https://w3c.github.io/encrypted-media/#key-system
+// that can be matched exactly with known DRM key systems of the platform.
+// When |key_system| is an empty string, the return value is an indication for
+// non-encrypted media.
+// Note that both |mime| and |key_system| cannot be NULL.  This function returns
+// kSbMediaSupportNotSupported if any of them is NULL.
+SB_EXPORT SbMediaSupportType
+SbMediaCanPlayMimeAndKeySystem(const char* mime, const char* key_system);
+
 // Returns the number of audio outputs currently available on this device.  It
 // is expected that, even if the number of outputs or their audio configurations
 // can't be determined, the platform will at least return a single output that
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 3761520..ff62b59 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -173,6 +173,7 @@
         'string_find_string_test.cc',
         'string_format_test.cc',
         'string_format_wide_test.cc',
+        'string_parse_double_test.cc',
         'string_parse_signed_integer_test.cc',
         'string_parse_uint64_test.cc',
         'string_parse_unsigned_integer_test.cc',
diff --git a/src/starboard/nplb/string_parse_double_test.cc b/src/starboard/nplb/string_parse_double_test.cc
new file mode 100644
index 0000000..1197167
--- /dev/null
+++ b/src/starboard/nplb/string_parse_double_test.cc
@@ -0,0 +1,250 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Here we are not trying to do anything comprehensive, just to sanity check
+// that this is hooked up to something.
+
+#include <float.h>  // for DBL_MIN
+#include <math.h>   // for HUGE_VAL
+#include "starboard/double.h"
+#include "starboard/string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// positive number
+TEST(SbStringParseDoubleTest, Positive) {
+  const char kDouble[] = "  123.4";
+  const double kExpected = 123.4;
+  char* end = NULL;
+  EXPECT_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 7, end);
+}
+
+// positive number without decimal
+TEST(SbStringParseDoubleTest, PositiveNoDecimal) {
+  const char kDouble[] = "  123";
+  const double kExpected = 123;
+  char* end = NULL;
+  EXPECT_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 5, end);
+}
+
+// negative number
+TEST(SbStringParseDoubleTest, Negative) {
+  const char kDouble[] = "  -123.4";
+  const double kExpected = -123.4;
+  char* end = NULL;
+  EXPECT_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+// zero (in case it gets confused with null)
+TEST(SbStringParseDoubleTest, Zero) {
+  const char kDouble[] = "0";
+  const double kExpected = 0;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 1, end);
+}
+
+TEST(SbStringParseDoubleTest, TabSpacesNewLinePrefix) {
+  const char kDouble[] = "\t \n123.5";
+  const double kExpected = 123.5;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, TabSpacesNewLineSuffix) {
+  const char kDouble[] = "123.5\t \n";
+  const double kExpected = 123.5;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 5, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificLowerCasePositiveExp) {
+  const char kDouble[] = "123.5e2";
+  const double kExpected = 12350;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 7, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificLowerCasePositiveExp2) {
+  const char kDouble[] = "123.5e+2";
+  const double kExpected = 12350;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificLowerCaseNegativeExp) {
+  const char kDouble[] = "123.5e-2";
+  const double kExpected = 1.235;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificUpperCasePositiveExp) {
+  const char kDouble[] = "123.5E2";
+  const double kExpected = 12350;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 7, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificUpperCasePositiveExp2) {
+  const char kDouble[] = "123.5E+2";
+  const double kExpected = 12350;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, ScientificUpperCaseNegativeExp) {
+  const char kDouble[] = "123.5E-2";
+  const double kExpected = 1.235;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, Empty) {
+  const char kDouble[] = "";
+  const double kExpected = 0.0;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 0, end);
+}
+
+TEST(SbStringParseDoubleTest, Space) {
+  const char kDouble[] = " ";
+  const double kExpected = 0.0;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 0, end);
+}
+
+TEST(SbStringParseDoubleTest, AlphaNumerics) {
+  const char kDouble[] = "alskjdfkldd2";
+  const double kExpected = 0.0;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 0, end);
+}
+
+// out of bounds
+TEST(SbStringParseDoubleTest, Huge) {
+  const char kDouble[] = "9e9999";
+  const double kExpected = HUGE_VAL;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 6, end);
+}
+
+TEST(SbStringParseDoubleTest, HugeNeg) {
+  const char kDouble[] = "-9e9999";
+  const double kExpected = -HUGE_VAL;
+  char* end = NULL;
+  EXPECT_DOUBLE_EQ(kExpected, SbStringParseDouble(kDouble, &end));
+  EXPECT_EQ(kDouble + 7, end);
+}
+
+TEST(SbStringParseDoubleTest, Small) {
+  const char kDouble[] = "1e-310";
+  const double kExpected = DBL_MIN;
+  char* end = NULL;
+  double answer(SbStringParseDouble(kDouble, &end));
+  EXPECT_GE(kExpected, answer);
+  EXPECT_GT(answer, 0.0);
+  EXPECT_EQ(kDouble + 6, end);
+}
+
+TEST(SbStringParseDoubleTest, SmallNeg) {
+  const char kDouble[] = "-1e-310";
+  const double kExpected = -DBL_MIN;
+  char* end = NULL;
+  double answer(SbStringParseDouble(kDouble, &end));
+  EXPECT_LE(kExpected, answer);
+  EXPECT_LT(answer, 0.0);
+  EXPECT_EQ(kDouble + 7, end);
+}
+
+// The following tests are disabled until we decide we want to mimic
+// C11 behavior in Starboard.  NAN and INF supported was added in C11
+// test NAN, and INFINITY
+TEST(SbStringParseDoubleTest, NaN) {
+  const char kNanDoubles[][4] = {"nan", "naN", "nAn", "nAN",
+                                 "Nan", "NaN", "NAn", "NAN"};
+  const double kExpected = NAN;
+  char* end = NULL;
+  for (size_t i(0); i != sizeof(kNanDoubles) / sizeof(kNanDoubles[0]); ++i) {
+    EXPECT_TRUE(SbDoubleIsNan(SbStringParseDouble(kNanDoubles[i], &end)));
+    EXPECT_EQ(kNanDoubles[i] + 3, end);
+  }
+}
+
+TEST(SbStringParseDoubleTest, PosInf) {
+  const char kInfDoubles[][4] = {"inf", "inF", "iNf", "iNF",
+                                 "Inf", "InF", "INf", "INF"};
+  char* end = NULL;
+  for (size_t i(0); i != sizeof(kInfDoubles) / sizeof(kInfDoubles[0]); ++i) {
+    EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfDoubles[i], &end)));
+    EXPECT_EQ(kInfDoubles[i] + 3, end);
+  }
+
+  const char kInfinity[] = "InFinIty";
+  end = NULL;
+  EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfinity, &end)));
+  EXPECT_EQ(kInfinity + 8, end);
+}
+
+TEST(SbStringParseDoubleTest, PosInf2) {
+  const char kInfDoubles[][5] = {"+inf", "+inF", "+iNf", "+iNF",
+                                 "+Inf", "+InF", "+INf", "+INF"};
+  char* end = NULL;
+  for (size_t i(0); i != sizeof(kInfDoubles) / sizeof(kInfDoubles[0]); ++i) {
+    EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfDoubles[i], &end)));
+    EXPECT_EQ(kInfDoubles[i] + 4, end);
+  }
+
+  const char kInfinity[] = "+InFinIty";
+  end = NULL;
+  EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfinity, &end)));
+  EXPECT_EQ(kInfinity + 9, end);
+}
+
+TEST(SbStringParseDoubleTest, NegInf) {
+  const char kInfDoubles[][5] = {"-inf", "-inF", "-iNf", "-iNF",
+                                 "-Inf", "-InF", "-INf", "-INF"};
+  char* end = NULL;
+  for (size_t i(0); i != sizeof(kInfDoubles) / sizeof(kInfDoubles[0]); ++i) {
+    EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfDoubles[i], &end)));
+    EXPECT_EQ(kInfDoubles[i] + 4, end);
+  }
+
+  const char kInfinity[] = "-InFinIty";
+  end = NULL;
+  EXPECT_FALSE(SbDoubleIsFinite(SbStringParseDouble(kInfinity, &end)));
+  EXPECT_EQ(kInfinity + 9, end);
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/src/starboard/nplb/system_hide_splash_screen_test.cc b/src/starboard/nplb/system_hide_splash_screen_test.cc
index a97392e..acf3657 100644
--- a/src/starboard/nplb/system_hide_splash_screen_test.cc
+++ b/src/starboard/nplb/system_hide_splash_screen_test.cc
@@ -16,12 +16,18 @@
 // this is hooked up to something.
 
 #include "starboard/system.h"
+#include "starboard/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace starboard {
 namespace nplb {
 namespace {
 
+void* ThreadFunc(void* context) {
+  SbSystemHideSplashScreen();
+  return NULL;
+}
+
 TEST(SbSystemHideSplashScreenTest, SunnyDay) {
   // Function returns no result, and correct execution cannot be determined
   // programatically, but we should at least be able to call it twice without
@@ -30,6 +36,16 @@
   SbSystemHideSplashScreen();
 }
 
+TEST(SbSystemHideSplashScreenTest, SunnyDayNewThread) {
+  // We should be able to call the function from any thread.
+  const char kThreadName[] = "HideSplashTest";
+  SbThread thread = SbThreadCreate(0 /*stack_size*/, kSbThreadPriorityNormal,
+                                   kSbThreadNoAffinity, true /*joinable*/,
+                                   kThreadName, ThreadFunc, NULL /*context*/);
+  EXPECT_TRUE(SbThreadIsValid(thread));
+  SbThreadJoin(thread, NULL /*out_return*/);
+}
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi
index 13f0753..67a0ee9 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -21,6 +21,7 @@
     'in_app_dial%': 0,
     'sysroot%': '/',
     'gl_type': 'system_gles2',
+    'image_cache_size_in_bytes': 32 * 1024 * 1024,
 
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index 7206d0c..e66dd31 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -88,6 +88,7 @@
         '<(DEPTH)/starboard/shared/iso/string_find_string.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length.cc',
         '<(DEPTH)/starboard/shared/iso/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_double.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_signed_integer.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_uint64.cc',
         '<(DEPTH)/starboard/shared/iso/string_parse_unsigned_integer.cc',
@@ -225,8 +226,11 @@
         '<(DEPTH)/starboard/shared/starboard/log_message.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_dump_stack.cc',
         '<(DEPTH)/starboard/shared/starboard/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
         '<(DEPTH)/starboard/shared/starboard/new.cc',
         '<(DEPTH)/starboard/shared/starboard/player/audio_decoder_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/audio_renderer_internal.cc',
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
index 784947a..be5a4ba 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
@@ -90,9 +90,14 @@
   int frame_decoded = 0;
   int result =
       avcodec_decode_audio4(codec_context_, av_frame_, &frame_decoded, &packet);
-  SB_DCHECK(result == input_buffer.size())
-      << result << " " << input_buffer.size() << " " << frame_decoded;
-  SB_DCHECK(frame_decoded == 1);
+  if (result != input_buffer.size() || frame_decoded != 1) {
+    // TODO: Consider fill it with silence.
+    SB_DLOG(WARNING) << "avcodec_decode_audio4() failed with result: " << result
+                     << " with input buffer size: " << input_buffer.size()
+                     << " and frame decoded: " << frame_decoded;
+    output->clear();
+    return;
+  }
 
   int decoded_audio_size = av_samples_get_buffer_size(
       NULL, codec_context_->channels, av_frame_->nb_samples,
@@ -106,6 +111,7 @@
         audio_header_.samples_per_second, av_frame_->nb_samples,
         av_frame_->extended_data, reinterpret_cast<uint8_t*>(&(*output)[0]));
   } else {
+    // TODO: Consider fill it with silence.
     SB_LOG(ERROR) << "Decoded audio frame is empty.";
     output->clear();
   }
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index d087ab9..5174f70 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -38,11 +38,9 @@
 }
 
 int AllocateBuffer(AVCodecContext* codec_context, AVFrame* frame) {
-  SB_DCHECK(codec_context->pix_fmt == PIX_FMT_YUV420P ||
-            codec_context->pix_fmt == PIX_FMT_YUVJ420P)
-      << "Invalid pix_fmt " << codec_context->pix_fmt;
   if (codec_context->pix_fmt != PIX_FMT_YUV420P &&
       codec_context->pix_fmt != PIX_FMT_YUVJ420P) {
+    SB_DLOG(WARNING) << "Unsupported pix_fmt " << codec_context->pix_fmt;
     return AVERROR(EINVAL);
   }
 
diff --git a/src/starboard/shared/iso/string_parse_double.cc b/src/starboard/shared/iso/string_parse_double.cc
new file mode 100644
index 0000000..6a51e52
--- /dev/null
+++ b/src/starboard/shared/iso/string_parse_double.cc
@@ -0,0 +1,23 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/string.h"
+
+#include <stdlib.h>
+#include "starboard/log.h"
+
+double SbStringParseDouble(const char* start, char** out_end) {
+  SB_DCHECK(start != NULL) << "start must be a valid pointer";
+  return strtod(start, out_end);
+}
diff --git a/src/starboard/shared/signal/crash_signals_sigaction.cc b/src/starboard/shared/signal/crash_signals_sigaction.cc
new file mode 100644
index 0000000..735e506
--- /dev/null
+++ b/src/starboard/shared/signal/crash_signals_sigaction.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/signal/crash_signals.h"
+
+#include <signal.h>
+
+#include "starboard/configuration.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/system.h"
+
+namespace starboard {
+namespace shared {
+namespace signal {
+
+namespace {
+
+const int kSignalsToTrap[] = {
+    SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV,
+};
+
+const char* GetSignalName(int signal_id) {
+  switch (signal_id) {
+    case SIGABRT:
+      return "SIGABRT";
+    case SIGFPE:
+      return "SIGFPE";
+    case SIGILL:
+      return "SIGILL";
+    case SIGINT:
+      return "SIGINT";
+    case SIGSEGV:
+      return "SIGSEGV";
+    default:
+      return "UNKNOWN SIGNAL";
+  }
+}
+
+typedef void (*SignalHandlerFunction)(int);
+
+void SetSignalHandler(int signal_id, SignalHandlerFunction handler) {
+    struct sigaction action = {0};
+
+    action.sa_handler = handler;
+    action.sa_flags = 0;
+    ::sigemptyset(&action.sa_mask);
+
+    ::sigaction(signal_id, &action, NULL);
+}
+
+void DumpStackSignalSafe(int signal_id) {
+  const char* signal_name = GetSignalName(signal_id);
+  SbLogRawFormatF("\nCaught signal: %s (%d)\n", signal_name, signal_id);
+  SbLogFlush();
+  SbLogRawDumpStack(1);
+
+  UninstallCrashSignalHandlers();
+  SbSystemBreakIntoDebugger();
+}
+
+}  // namespace
+
+void InstallCrashSignalHandlers() {
+  for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
+    SetSignalHandler(kSignalsToTrap[i], &DumpStackSignalSafe);
+  }
+}
+
+void UninstallCrashSignalHandlers() {
+  for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
+    SetSignalHandler(kSignalsToTrap[i], SIG_DFL);
+  }
+}
+
+}  // namespace signal
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
new file mode 100644
index 0000000..9bfd9a7
--- /dev/null
+++ b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
@@ -0,0 +1,67 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/media.h"
+
+#include "starboard/character.h"
+#include "starboard/log.h"
+#include "starboard/shared/starboard/media/mime_parser.h"
+#include "starboard/string.h"
+
+using starboard::shared::starboard::media::MimeParser;
+
+SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime,
+                                                  const char* key_system) {
+  if (mime == NULL) {
+    SB_DLOG(WARNING) << "mime cannot be NULL";
+    return kSbMediaSupportTypeNotSupported;
+  }
+  if (key_system == NULL) {
+    SB_DLOG(WARNING) << "key_system cannot be NULL";
+    return kSbMediaSupportTypeNotSupported;
+  }
+  if (SbStringGetLength(key_system) != 0) {
+    if (!SbMediaIsSupported(kSbMediaVideoCodecNone, kSbMediaAudioCodecNone,
+                            key_system)) {
+      return kSbMediaSupportTypeNotSupported;
+    }
+  }
+  MimeParser parser(mime);
+  if (!parser.is_valid()) {
+    SB_DLOG(WARNING) << mime << " is not a valid mime type";
+    return kSbMediaSupportTypeNotSupported;
+  }
+  if (parser.mime() == "application/octet-stream") {
+    return kSbMediaSupportTypeProbably;
+  }
+  if (parser.mime() == "audio/mp4") {
+    return kSbMediaSupportTypeProbably;
+  }
+  if (parser.mime() == "video/mp4") {
+    return kSbMediaSupportTypeProbably;
+  }
+#if SB_HAS(MEDIA_WEBM_VP9_SUPPORT)
+  if (parser.mime() == "video/webm") {
+    if (!parser.HasParam("codecs")) {
+      return kSbMediaSupportTypeMaybe;
+    }
+    std::string codecs = parser.GetParam("codecs");
+    if (codecs == "vp9") {
+      return kSbMediaSupportTypeProbably;
+    }
+    return kSbMediaSupportTypeNotSupported;
+  }
+#endif  // SB_HAS(MEDIA_WEBM_VP9_SUPPORT)
+  return kSbMediaSupportTypeNotSupported;
+}
diff --git a/src/starboard/shared/starboard/media/mime_parser.cc b/src/starboard/shared/starboard/media/mime_parser.cc
new file mode 100644
index 0000000..7db734a
--- /dev/null
+++ b/src/starboard/shared/starboard/media/mime_parser.cc
@@ -0,0 +1,141 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/starboard/media/mime_parser.h"
+
+#include <vector>
+
+#include "starboard/character.h"
+#include "starboard/log.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+
+namespace {
+
+void ToLower(std::string* string) {
+  SB_DCHECK(string);
+  for (size_t i = 0; i < string->size(); ++i) {
+    (*string)[i] = SbCharacterToLower((*string)[i]);
+  }
+}
+
+void Trim(std::string* string) {
+  SB_DCHECK(string);
+  while (!string->empty() && SbCharacterIsSpace(*string->rbegin())) {
+    string->resize(string->size() - 1);
+  }
+  while (!string->empty() && SbCharacterIsSpace(*string->begin())) {
+    string->erase(string->begin());
+  }
+}
+
+bool IsSeparator(char ch, std::string separator) {
+  if (separator.empty()) {
+    return SbCharacterIsSpace(ch);
+  }
+  return separator.find(ch) != separator.npos;
+}
+
+// For any given string, split it into substrings separated by any character in
+// the |separator| string.  If |separator| is empty string, treat any white
+// space as separators.
+std::vector<std::string> SplitString(std::string string,
+                                     std::string separator = "") {
+  std::vector<std::string> result;
+  while (!string.empty()) {
+    Trim(&string);
+    if (string.empty()) {
+      break;
+    }
+    bool added = false;
+    for (size_t i = 0; i < string.size(); ++i) {
+      if (IsSeparator(string[i], separator)) {
+        result.push_back(string.substr(0, i));
+        Trim(&result.back());
+        string = string.substr(i + 1);
+        added = true;
+        break;
+      }
+    }
+    if (!added) {
+      Trim(&string);
+      result.push_back(string);
+      break;
+    }
+  }
+  return result;
+}
+
+}  // namespace
+
+MimeParser::MimeParser(std::string mime_with_params) {
+  Trim(&mime_with_params);
+  ToLower(&mime_with_params);
+
+  std::vector<std::string> splits = SplitString(mime_with_params, ";");
+  if (splits.empty()) {
+    return;  // It is invalid, leave |mime_| as empty.
+  }
+  mime_ = splits[0];
+  // Mime is in the form of "video/mp4".
+  if (SplitString(mime_, "/").size() != 2) {
+    mime_.clear();
+    return;
+  }
+  splits.erase(splits.begin());
+
+  while (!splits.empty()) {
+    std::string params = *splits.begin();
+    splits.erase(splits.begin());
+
+    // Param is in the form of 'name=value' or 'name="value"'.
+    std::vector<std::string> name_and_value = SplitString(params, "=");
+    if (name_and_value.size() != 2) {
+      mime_.clear();
+      return;
+    }
+    std::string name = name_and_value[0];
+    std::string value = name_and_value[1];
+
+    if (value.size() >= 2 && value[0] == '\"' &&
+        value[value.size() - 1] == '\"') {
+      value.erase(value.begin());
+      value.resize(value.size() - 1);
+      Trim(&value);
+    }
+
+    params_[name] = value;
+  }
+}
+
+bool MimeParser::HasParam(const std::string& name) const {
+  return params_.find(name) != params_.end();
+}
+
+std::string MimeParser::GetParam(const std::string& name) const {
+  std::map<std::string, std::string>::const_iterator iter = params_.find(name);
+  if (iter == params_.end()) {
+    return "";
+  }
+  return iter->second;
+}
+
+}  // namespace media
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/starboard/media/mime_parser.h b/src/starboard/shared/starboard/media/mime_parser.h
new file mode 100644
index 0000000..b896b2d
--- /dev/null
+++ b/src/starboard/shared/starboard/media/mime_parser.h
@@ -0,0 +1,54 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
+#define STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
+
+#include <map>
+#include <string>
+
+#include "starboard/shared/internal_only.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+
+// This class can be used to parse media mime types with params.  For example,
+// the following mime type 'video/mp4; codecs="avc1.4d401e"; width=640' will be
+// parsed into:
+//   mime => video/mp4
+//     param: codecs => avc1.4d401e
+//     param: width  => 640
+class MimeParser {
+ public:
+  explicit MimeParser(std::string mime_with_params);
+
+  bool is_valid() const { return !mime_.empty(); }
+  const std::string& mime() const { return mime_; }
+
+  bool HasParam(const std::string& name) const;
+  std::string GetParam(const std::string& name) const;
+
+ private:
+  std::string mime_;
+  std::map<std::string, std::string> params_;
+};
+
+}  // namespace media
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
diff --git a/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc b/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc
new file mode 100644
index 0000000..34a9b16
--- /dev/null
+++ b/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc
@@ -0,0 +1,20 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/media.h"
+
+SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime,
+                                                  const char* key_system) {
+  return kSbMediaSupportTypeNotSupported;
+}
diff --git a/src/starboard/shared/stub/string_parse_double.cc b/src/starboard/shared/stub/string_parse_double.cc
new file mode 100644
index 0000000..7ac141b
--- /dev/null
+++ b/src/starboard/shared/stub/string_parse_double.cc
@@ -0,0 +1,21 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/string.h"
+
+double SbStringParseDouble(const char* start, char** out_end) {
+  if (out_end != NULL)
+    *out_end = NULL;
+  return 0.0;
+}
diff --git a/src/starboard/shared/stub/system_raise_platform_error.cc b/src/starboard/shared/stub/system_raise_platform_error.cc
index 4a80cb1..13303cb 100644
--- a/src/starboard/shared/stub/system_raise_platform_error.cc
+++ b/src/starboard/shared/stub/system_raise_platform_error.cc
@@ -38,5 +38,5 @@
       break;
   }
   SB_DLOG(INFO) << "SbSystemRaisePlatformError: " << message;
-  return false;
+  return kSbSystemPlatformErrorInvalid;
 }
diff --git a/src/starboard/string.h b/src/starboard/string.h
index e8193c0..9b72dfa 100644
--- a/src/starboard/string.h
+++ b/src/starboard/string.h
@@ -36,16 +36,18 @@
 
 // Copies as much |source| as possible into |out_destination| and
 // null-terminates it, given that it has |destination_size| characters of
-// storage available. Returns the length of |source|.
+// storage available.  Returns the length of |source|.  Meant to be a drop-in
+// replacement for strlcpy
 SB_EXPORT int SbStringCopy(char* out_destination,
                            const char* source,
                            int destination_size);
 
 // Inline wrapper for an unsafe SbStringCopy that assumes |out_destination| is
 // big enough. Meant to be a drop-in replacement for strcpy.
-static SB_C_INLINE int SbStringCopyUnsafe(char* out_destination,
-                                          const char* source) {
-  return SbStringCopy(out_destination, source, INT_MAX);
+static SB_C_INLINE char* SbStringCopyUnsafe(char* out_destination,
+                                            const char* source) {
+  SbStringCopy(out_destination, source, INT_MAX);
+  return out_destination;
 }
 
 // Same as SbStringCopy but for wide characters.
@@ -54,14 +56,16 @@
                                int destination_size);
 
 // Concatenates |source| onto the end of |out_destination|, presuming it has
-// |destination_size| total characters of storage available. Returns the length
-// of |source|.
+// |destination_size| total characters of storage available. Returns
+// length of |source|. Meant to be a drop-in replacement for strlcpy
+// Note: This function's signature is NOT compatible with strncat
 SB_EXPORT int SbStringConcat(char* out_destination,
                              const char* source,
                              int destination_size);
 
 // Inline wrapper for an unsafe SbStringConcat that assumes |out_destination| is
-// big enough. Meant to be a drop-in replacement for strcat.
+// big enough.
+// Note: This function's signature is NOT compatible with strcat.
 static SB_C_INLINE int SbStringConcatUnsafe(char* out_destination,
                                             const char* source) {
   return SbStringConcat(out_destination, source, INT_MAX);
@@ -77,13 +81,15 @@
 SB_EXPORT char* SbStringDuplicate(const char* source);
 
 // Finds the first occurrence of |character| in |str|, returning a pointer to
-// the found character in the given string, or NULL if not found. Meant to be a
-// drop-in replacement for strchr.
+// the found character in the given string, or NULL if not found.
+// NOTE: The function signature of this function does NOT match the function
+// strchr.
 SB_EXPORT const char* SbStringFindCharacter(const char* str, char character);
 
 // Finds the last occurrence of |character| in |str|, returning a pointer to the
-// found character in the given string, or NULL if not found. Meant to be a
-// drop-in replacement for strrchr.
+// found character in the given string, or NULL if not found.
+// NOTE: The function signature of this function does NOT match the function
+// strrchr.
 SB_EXPORT const char* SbStringFindLastCharacter(const char* str,
                                                 char character);
 
@@ -233,7 +239,7 @@
 // Parses a string at the beginning of |start| into a unsigned integer in the
 // given |base|.  It will place the pointer to the end of the consumed portion
 // of the string in |out_end|, if it is provided. Meant to be a drop-in
-// replacement for strtol.
+// replacement for strtoul.
 // NOLINTNEXTLINE(runtime/int)
 SB_EXPORT unsigned long SbStringParseUnsignedInteger(const char* start,
                                                      char** out_end,
@@ -247,6 +253,12 @@
                                        char** out_end,
                                        int base);
 
+// Parses a string at the beginning of |start| into a double.
+// It will place the pointer to the end of the consumed
+// portion of the string in |out_end|, if it is provided. Meant to be a drop-in
+// replacement for strtod, but explicity declared to return double.
+SB_EXPORT double SbStringParseDouble(const char* start, char** out_end);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index e871191..21054dc 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -80,6 +80,7 @@
         '<(DEPTH)/starboard/shared/stub/log_raw.cc',
         '<(DEPTH)/starboard/shared/stub/log_raw_dump_stack.cc',
         '<(DEPTH)/starboard/shared/stub/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/stub/media_can_play_mime_and_key_system.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_output_protected.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
         '<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc',
@@ -163,6 +164,7 @@
         '<(DEPTH)/starboard/shared/stub/string_format_wide.cc',
         '<(DEPTH)/starboard/shared/stub/string_get_length.cc',
         '<(DEPTH)/starboard/shared/stub/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_parse_double.cc',
         '<(DEPTH)/starboard/shared/stub/string_parse_signed_integer.cc',
         '<(DEPTH)/starboard/shared/stub/string_parse_uint64.cc',
         '<(DEPTH)/starboard/shared/stub/string_parse_unsigned_integer.cc',
diff --git a/src/third_party/mozjs/cobalt_config/include/js-confdefs.h b/src/third_party/mozjs/cobalt_config/include/js-confdefs.h
index d5c09af..28f22d6 100644
--- a/src/third_party/mozjs/cobalt_config/include/js-confdefs.h
+++ b/src/third_party/mozjs/cobalt_config/include/js-confdefs.h
@@ -20,6 +20,11 @@
 #define RELEASE_BUILD 1
 #endif
 
+#if defined(COBALT_BUILD_TYPE_DEBUG)
+#define DEBUG 1
+#define JS_DEBUG 1
+#endif
+
 // Disabling this will fall back to getenv for locale-specific number
 // formatting.
 // This can be removed when ENABLE_INTL_API is enabled, which requires a newer
diff --git a/src/third_party/mozjs/js/public/Value.h b/src/third_party/mozjs/js/public/Value.h
index 72b3f38..f2345f4 100644
--- a/src/third_party/mozjs/js/public/Value.h
+++ b/src/third_party/mozjs/js/public/Value.h
@@ -819,6 +819,10 @@
     return mozilla::SpecificNaN(0, 0x8000000000000ULL);
 }
 
+/* MSVC with PGO miscompiles this function. */
+#if defined(_MSC_VER)
+# pragma optimize("g", off)
+#endif
 static inline double
 CanonicalizeNaN(double d)
 {
@@ -826,6 +830,9 @@
         return GenericNaN();
     return d;
 }
+#if defined(_MSC_VER)
+# pragma optimize("", on)
+#endif
 
 /*
  * JS::Value is the interface for a single JavaScript Engine value.  A few
diff --git a/src/third_party/mozjs/js/src/builtin/TestingFunctions.cpp b/src/third_party/mozjs/js/src/builtin/TestingFunctions.cpp
index 24cb2d7..239938f 100644
--- a/src/third_party/mozjs/js/src/builtin/TestingFunctions.cpp
+++ b/src/third_party/mozjs/js/src/builtin/TestingFunctions.cpp
@@ -744,7 +744,7 @@
     return true;
 }
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(JS_USE_CUSTOM_ALLOCATOR)
 static JSBool
 OOMAfterAllocations(JSContext *cx, unsigned argc, jsval *vp)
 {
@@ -1028,7 +1028,7 @@
 "  count all things or one of 'object', 'double', 'string', 'function'\n"
 "  to count only things of that kind."),
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(JS_USE_CUSTOM_ALLOCATOR)
     JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
 "oomAfterAllocations(count)",
 "  After 'count' js_malloc memory allocations, fail every following allocation\n"
diff --git a/src/third_party/mozjs/js/src/ds/LifoAlloc.h b/src/third_party/mozjs/js/src/ds/LifoAlloc.h
index f2fbb5a..25ea2d3 100644
--- a/src/third_party/mozjs/js/src/ds/LifoAlloc.h
+++ b/src/third_party/mozjs/js/src/ds/LifoAlloc.h
@@ -288,18 +288,17 @@
 
     template <typename T>
     T *newArray(size_t count) {
-        void *mem = alloc(sizeof(T) * count);
-        if (!mem)
-            return NULL;
         JS_STATIC_ASSERT(mozilla::IsPod<T>::value);
-        return (T *) mem;
+        return newArrayUninitialized<T>(count);
     }
 
     // Create an array with uninitialized elements of type |T|.
     // The caller is responsible for initialization.
     template <typename T>
     T *newArrayUninitialized(size_t count) {
-        return static_cast<T *>(alloc(sizeof(T) * count));
+        if (count & tl::MulOverflowMask<sizeof(T)>::result)
+            return NULL;
+       return static_cast<T *>(alloc(sizeof(T) * count));
     }
 
     class Mark {
diff --git a/src/third_party/mozjs/js/src/jit/FixedList.h b/src/third_party/mozjs/js/src/jit/FixedList.h
index d21ae87..54a582f 100644
--- a/src/third_party/mozjs/js/src/jit/FixedList.h
+++ b/src/third_party/mozjs/js/src/jit/FixedList.h
@@ -23,7 +23,7 @@
 
   public:
     FixedList()
-      : length_(0)
+            : length_(0), list_(NULL)
     { }
 
     // Dynamic memory allocation requires the ability to report failure.
@@ -32,6 +32,8 @@
         if (length == 0)
             return true;
 
+        if (length & tl::MulOverflowMask<sizeof(T)>::result)
+            return false;
         list_ = (T *)GetIonContext()->temp->allocate(length * sizeof(T));
         return list_ != NULL;
     }
@@ -46,6 +48,11 @@
     }
 
     bool growBy(size_t num) {
+        size_t newlength = length_ + num;
+        if (newlength < length_)
+            return false;
+        if (newlength & tl::MulOverflowMask<sizeof(T)>::result)
+            return false;
         T *list = (T *)GetIonContext()->temp->allocate((length_ + num) * sizeof(T));
         if (!list)
             return false;
diff --git a/src/third_party/mozjs/js/src/jit/IonBuilder.cpp b/src/third_party/mozjs/js/src/jit/IonBuilder.cpp
index a0c70f5..00fd7a0 100644
--- a/src/third_party/mozjs/js/src/jit/IonBuilder.cpp
+++ b/src/third_party/mozjs/js/src/jit/IonBuilder.cpp
@@ -5005,6 +5005,7 @@
         // MCall accordingly.
         types::StackTypeSet *thisTypes = thisArg->resultTypeSet();
         if (thisTypes &&
+            thisTypes->getKnownTypeTag() == JSVAL_TYPE_OBJECT &&
             TestAreKnownDOMTypes(cx, thisTypes) &&
             TestShouldDOMCall(cx, thisTypes, target, JSJitInfo::Method))
         {
diff --git a/src/third_party/mozjs/js/src/jit/IonCaches.cpp b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
index f833d0f..a7ce25d 100644
--- a/src/third_party/mozjs/js/src/jit/IonCaches.cpp
+++ b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
@@ -594,8 +594,19 @@
     if (!shape->hasGetterValue() || !shape->getterValue().isObject())
         return false;
 
-    return shape->getterValue().toObject().is<JSFunction>() &&
-           shape->getterValue().toObject().as<JSFunction>().isNative();
+    if (!shape->getterValue().toObject().is<JSFunction>())
+        return false;
+
+    JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
+    if (!getter.isNative())
+        return false;
+
+    // Check for a DOM method; those are OK with both inner and outer objects.
+    if (getter.jitInfo())
+        return true;
+
+    // For non-DOM methods, don't cache if obj has an outerObject hook.
+    return !obj->getClass()->ext.outerObject;
 }
 
 static bool
diff --git a/src/third_party/mozjs/js/src/jit/MIR.h b/src/third_party/mozjs/js/src/jit/MIR.h
index 17d8f7e..ef1df1b 100644
--- a/src/third_party/mozjs/js/src/jit/MIR.h
+++ b/src/third_party/mozjs/js/src/jit/MIR.h
@@ -77,8 +77,6 @@
 class MIRGraph;
 class MResumePoint;
 
-static inline bool isOSRLikeValue (MDefinition *def);
-
 // Represents a use of a node.
 class MUse : public TempObject, public InlineListNode<MUse>
 {
@@ -213,14 +211,16 @@
         FixedSlot         = 1 << 3, // A member of obj->fixedSlots().
         TypedArrayElement = 1 << 4, // A typed array element.
         DOMProperty       = 1 << 5, // A DOM property
-        Last              = DOMProperty,
+        TypedArrayLength  = 1 << 6,// A typed array's length
+        Last              = TypedArrayLength,
         Any               = Last | (Last - 1),
 
-        NumCategories     = 6,
+        NumCategories     = 7,
 
         // Indicates load or store.
         Store_            = 1 << 31
     };
+
     AliasSet(uint32_t flags)
       : flags_(flags)
     {
@@ -4339,9 +4339,7 @@
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
-        // The typed array |length| property is immutable, so there is no
-        // implicit dependency.
-        return AliasSet::None();
+        return AliasSet::Load(AliasSet::TypedArrayLength);
     }
 };
 
@@ -8264,17 +8262,6 @@
     return (MInstruction *)this;
 }
 
-static inline bool isOSRLikeValue (MDefinition *def) {
-    if (def->isOsrValue())
-        return true;
-
-    if (def->isUnbox())
-        if (def->getOperand(0)->isOsrValue())
-            return true;
-
-    return false;
-}
-
 typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector;
 
 // Helper functions used to decide how to build MIR.
diff --git a/src/third_party/mozjs/js/src/jit/MIRGenerator.h b/src/third_party/mozjs/js/src/jit/MIRGenerator.h
index ee28baa..1e3316f 100644
--- a/src/third_party/mozjs/js/src/jit/MIRGenerator.h
+++ b/src/third_party/mozjs/js/src/jit/MIRGenerator.h
@@ -60,6 +60,8 @@
 
     template <typename T>
     T * allocate(size_t count = 1) {
+        if (count & tl::MulOverflowMask<sizeof(T)>::result)
+            return NULL;
         return reinterpret_cast<T *>(temp().allocate(sizeof(T) * count));
     }
 
diff --git a/src/third_party/mozjs/js/src/jit/MIRGraph.h b/src/third_party/mozjs/js/src/jit/MIRGraph.h
index 7ee362c..60c2ef4 100644
--- a/src/third_party/mozjs/js/src/jit/MIRGraph.h
+++ b/src/third_party/mozjs/js/src/jit/MIRGraph.h
@@ -542,11 +542,6 @@
         numBlocks_(0)
     { }
 
-    template <typename T>
-    T * allocate(size_t count = 1) {
-        return reinterpret_cast<T *>(alloc_->allocate(sizeof(T) * count));
-    }
-
     void addBlock(MBasicBlock *block);
     void insertBlockAfter(MBasicBlock *at, MBasicBlock *block);
 
diff --git a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
index c8cbc20..4381d84 100644
--- a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
+++ b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
@@ -536,16 +536,12 @@
         return;
 
     Range *range = NULL;
-    JS_ASSERT(getOperand(0)->op() != MDefinition::Op_OsrValue);
     for (size_t i = 0; i < numOperands(); i++) {
         if (getOperand(i)->block()->earlyAbort()) {
             IonSpew(IonSpew_Range, "Ignoring unreachable input %d", getOperand(i)->id());
             continue;
         }
 
-        if (isOSRLikeValue(getOperand(i)))
-            continue;
-
         Range *input = getOperand(i)->range();
 
         if (!input) {
diff --git a/src/third_party/mozjs/js/src/jsdbgapi.cpp b/src/third_party/mozjs/js/src/jsdbgapi.cpp
index 7021e16..08fc0bb 100644
--- a/src/third_party/mozjs/js/src/jsdbgapi.cpp
+++ b/src/third_party/mozjs/js/src/jsdbgapi.cpp
@@ -966,8 +966,11 @@
     for (NonBuiltinScriptFrameIter i(cx); !i.done(); ++i) {
         FrameDescription desc;
         desc.script = i.script();
-        desc.lineno = PCToLineNumber(i.script(), i.pc());
+        unsigned column = 0;
+        desc.lineno = PCToLineNumber(i.script(), i.pc(), &column);
         desc.fun = i.maybeCallee();
+        // Don't zero index.
+        desc.columnno = column + 1;
         if (!frames.append(desc))
             return NULL;
         if (frames.length() == maxFrames)
diff --git a/src/third_party/mozjs/js/src/jsdbgapi.h b/src/third_party/mozjs/js/src/jsdbgapi.h
index 9aadf53..cd19bd2 100644
--- a/src/third_party/mozjs/js/src/jsdbgapi.h
+++ b/src/third_party/mozjs/js/src/jsdbgapi.h
@@ -18,6 +18,7 @@
     JSScript *script;
     unsigned lineno;
     JSFunction *fun;
+    unsigned columnno;
 };
 
 struct StackDescription
diff --git a/src/third_party/mozjs/js/src/jsexn.cpp b/src/third_party/mozjs/js/src/jsexn.cpp
index fae9798..cdc2f51 100644
--- a/src/third_party/mozjs/js/src/jsexn.cpp
+++ b/src/third_party/mozjs/js/src/jsexn.cpp
@@ -76,6 +76,7 @@
     T                   funName;
     const char          *filename;
     unsigned            ulineno;
+    unsigned            ucolumnno;
 };
 
 typedef JSStackTraceElemImpl<HeapPtrString> JSStackTraceElem;
@@ -282,7 +283,10 @@
             if (!cfilename)
                 cfilename = "";
             frame.filename = cfilename;
-            frame.ulineno = PCToLineNumber(script, i.pc());
+            uint32_t column = 0;
+            frame.ulineno = PCToLineNumber(script, i.pc(), &column);
+            // Don't zero index.
+            frame.ucolumnno = column + 1;
         }
     }
 
@@ -327,6 +331,7 @@
         if (!priv->stackElems[i].filename)
             return false;
         priv->stackElems[i].ulineno = frames[i].ulineno;
+        priv->stackElems[i].ucolumnno = frames[i].ucolumnno;
     }
 
     SetExnPrivate(exnObject, priv);
@@ -510,7 +515,8 @@
             if (!sb.appendInflated(element->filename, strlen(element->filename)))
                 return NULL;
         }
-        if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(element->ulineno), sb) || 
+        if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(element->ulineno), sb) ||
+            !sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(element->ucolumnno), sb) ||
             !sb.append('\n'))
         {
             return NULL;
diff --git a/src/third_party/mozjs/js/src/jsinfer.cpp b/src/third_party/mozjs/js/src/jsinfer.cpp
index 93c93bf..3a26388 100644
--- a/src/third_party/mozjs/js/src/jsinfer.cpp
+++ b/src/third_party/mozjs/js/src/jsinfer.cpp
@@ -127,6 +127,9 @@
 
 static bool InferSpewColorable()
 {
+#if defined(STARBOARD)
+    return false;
+#else
     /* Only spew colors on xterm-color to not screw up emacs. */
     static bool colorable = false;
     static bool checked = false;
@@ -139,6 +142,7 @@
             colorable = true;
     }
     return colorable;
+#endif
 }
 
 const char *
@@ -6176,6 +6180,15 @@
 // Tracing
 /////////////////////////////////////////////////////////////////////
 
+static void
+CrashAtUnhandlableOOM(const char *reason)
+{
+    char msgbuf[1024];
+    JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
+    MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
+    MOZ_CRASH();
+}
+
 void
 TypeSet::sweep(Zone *zone)
 {
@@ -6200,10 +6213,9 @@
                 TypeObjectKey **pentry =
                     HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
                         (zone->types.typeLifoAlloc, objectSet, objectCount, object);
-                if (pentry)
-                    *pentry = object;
-                else
-                    zone->types.setPendingNukeTypes();
+                if (!pentry)
+                    CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
+                *pentry = object;
             }
         }
         setBaseObjectCount(objectCount);
@@ -6283,19 +6295,17 @@
             Property *prop = oldArray[i];
             if (prop && prop->types.ownProperty(false)) {
                 Property *newProp = typeLifoAlloc.new_<Property>(*prop);
-                if (newProp) {
-                    Property **pentry =
-                        HashSetInsert<jsid,Property,Property>
-                            (typeLifoAlloc, propertySet, propertyCount, prop->id);
-                    if (pentry) {
-                        *pentry = newProp;
-                        newProp->types.sweep(zone());
-                    } else {
-                        zone()->types.setPendingNukeTypes();
-                    }
-                } else {
-                    zone()->types.setPendingNukeTypes();
-                }
+                if (!newProp)
+                    CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+                Property **pentry =
+                    HashSetInsert<jsid,Property,Property>
+                        (typeLifoAlloc, propertySet, propertyCount, prop->id);
+                if (!pentry)
+                    CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+                *pentry = newProp;
+                newProp->types.sweep(zone());
             }
         }
         setBasePropertyCount(propertyCount);
@@ -6303,12 +6313,11 @@
         Property *prop = (Property *) propertySet;
         if (prop->types.ownProperty(false)) {
             Property *newProp = typeLifoAlloc.new_<Property>(*prop);
-            if (newProp) {
-                propertySet = (Property **) newProp;
-                newProp->types.sweep(zone());
-            } else {
-                zone()->types.setPendingNukeTypes();
-            }
+            if (!newProp)
+                CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+            propertySet = (Property **) newProp;
+            newProp->types.sweep(zone());
         } else {
             propertySet = NULL;
             setBasePropertyCount(0);
diff --git a/src/third_party/mozjs/js/src/jsinferinlines.h b/src/third_party/mozjs/js/src/jsinferinlines.h
index 6f86bba..8cebc8d 100644
--- a/src/third_party/mozjs/js/src/jsinferinlines.h
+++ b/src/third_party/mozjs/js/src/jsinferinlines.h
@@ -1131,19 +1131,21 @@
  * probing.  TODO: replace these with jshashtables.
  */
 const unsigned SET_ARRAY_SIZE = 8;
+const unsigned SET_CAPACITY_OVERFLOW = 1u << 30;
 
 /* Get the capacity of a set with the given element count. */
 static inline unsigned
 HashSetCapacity(unsigned count)
 {
     JS_ASSERT(count >= 2);
+    JS_ASSERT(count < SET_CAPACITY_OVERFLOW);
 
     if (count <= SET_ARRAY_SIZE)
         return SET_ARRAY_SIZE;
 
     unsigned log2;
     JS_FLOOR_LOG2(log2, count);
-    return 1 << (log2 + 2);
+    return 1u << (log2 + 2);
 }
 
 /* Compute the FNV hash for the low 32 bits of v. */
@@ -1181,6 +1183,9 @@
         }
     }
 
+    if (count >= SET_CAPACITY_OVERFLOW)
+        return NULL;
+
     count++;
     unsigned newCapacity = HashSetCapacity(count);
 
diff --git a/src/third_party/mozjs/js/src/jsobj.cpp b/src/third_party/mozjs/js/src/jsobj.cpp
index c8fc252..517b501 100644
--- a/src/third_party/mozjs/js/src/jsobj.cpp
+++ b/src/third_party/mozjs/js/src/jsobj.cpp
@@ -279,7 +279,6 @@
     if (pobj->isNative()) {
         desc->attrs = GetShapeAttributes(shape);
         if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
-            MOZ_ASSERT(desc.isShared());
             doGet = false;
             if (desc->attrs & JSPROP_GETTER)
                 desc->getter = CastAsPropertyOp(shape->getterObject());
diff --git a/src/third_party/mozjs/js/src/jspropertytree.cpp b/src/third_party/mozjs/js/src/jspropertytree.cpp
index 2fc39c0..170827c 100644
--- a/src/third_party/mozjs/js/src/jspropertytree.cpp
+++ b/src/third_party/mozjs/js/src/jspropertytree.cpp
@@ -344,6 +344,9 @@
 void
 js::PropertyTree::dumpShapes(JSRuntime *rt)
 {
+#if defined(STARBOARD)
+    return;
+#else
     static bool init = false;
     static FILE *dumpfp = NULL;
     if (!init) {
@@ -372,5 +375,6 @@
         }
         */
     }
+#endif
 }
 #endif
diff --git a/src/third_party/mozjs/js/src/jsproxy.cpp b/src/third_party/mozjs/js/src/jsproxy.cpp
index eddf34f..2dbad14 100644
--- a/src/third_party/mozjs/js/src/jsproxy.cpp
+++ b/src/third_party/mozjs/js/src/jsproxy.cpp
@@ -2328,9 +2328,7 @@
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
-    bool ok = handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
-    MOZ_ASSERT_IF(ok && desc.isShared(), desc.hasGetterOrSetterObject());
-    return ok;
+    return handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
diff --git a/src/third_party/mozjs/js/src/jsscript.cpp b/src/third_party/mozjs/js/src/jsscript.cpp
index f4db686..88d8a3b 100644
--- a/src/third_party/mozjs/js/src/jsscript.cpp
+++ b/src/third_party/mozjs/js/src/jsscript.cpp
@@ -40,6 +40,10 @@
 #include "vm/RegExpObject-inl.h"
 #include "vm/ScopeObject-inl.h"
 
+#ifdef USE_ZLIB
+#include "zlib.h"
+#endif
+
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
diff --git a/src/third_party/mozjs/js/src/jstypedarray.cpp b/src/third_party/mozjs/js/src/jstypedarray.cpp
index 53afdc1..8019563 100644
--- a/src/third_party/mozjs/js/src/jstypedarray.cpp
+++ b/src/third_party/mozjs/js/src/jstypedarray.cpp
@@ -623,39 +623,56 @@
 ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
                                  uint8_t **data)
 {
+    MOZ_ASSERT(cx);
+
     ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
     JSObject *views = *GetViewList(&buffer);
-    js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
-    if (buffer.hasDynamicElements() && !buffer.isAsmJSArrayBuffer()) {
+
+    uint32_t byteLen = buffer.byteLength();
+
+    js::ObjectElements *oldHeader = buffer.getElementsHeader();
+    js::ObjectElements *newHeader;
+
+    // If the ArrayBuffer's elements are transferrable, transfer ownership
+    // directly.  Otherwise we have to copy the data into new elements.
+    bool stolen = buffer.hasStealableContents();
+    if (stolen) {
+        newHeader = AllocateArrayBufferContents(cx, byteLen, NULL);
+        if (!newHeader)
+            return false;
+
         *GetViewList(&buffer) = NULL;
-        *contents = header;
+        *contents = oldHeader;
         *data = buffer.dataPointer();
 
-        buffer.setFixedElements();
-        header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
+        MOZ_ASSERT(!buffer.isAsmJSArrayBuffer(),
+                   "buffer won't be neutered by neuterAsmJSArrayBuffer");
+
+        buffer.elements = newHeader->elements();
     } else {
-        uint32_t length = buffer.byteLength();
-        js::ObjectElements *newheader =
-            AllocateArrayBufferContents(cx, length, buffer.dataPointer());
-        if (!newheader) {
-            js_ReportOutOfMemory(cx);
+        js::ObjectElements *headerCopy =
+            AllocateArrayBufferContents(cx, byteLen, buffer.dataPointer());
+        if (!headerCopy)
             return false;
-        }
 
-        ArrayBufferObject::setElementsHeader(newheader, length);
-        *contents = newheader;
-        *data = reinterpret_cast<uint8_t *>(newheader + 1);
-
+        *contents = headerCopy;
+        *data = reinterpret_cast<uint8_t *>(headerCopy + 1);
         if (buffer.isAsmJSArrayBuffer())
             ArrayBufferObject::neuterAsmJSArrayBuffer(buffer);
+
+        // Keep using the current elements.
+        newHeader = oldHeader;
     }
 
     // Neuter the donor ArrayBuffer and all views of it
-    ArrayBufferObject::setElementsHeader(header, 0);
+    uint32_t flags = newHeader->flags;
+    ArrayBufferObject::setElementsHeader(newHeader, 0);
+    newHeader->flags = flags;
     GetViewList(&buffer)->init(views);
     for (JSObject *view = views; view; view = NextView(view))
         TypedArray::neuter(view);
 
+    newHeader->setIsNeuteredBuffer();
     return true;
 }
 
diff --git a/src/third_party/mozjs/js/src/jstypedarray.h b/src/third_party/mozjs/js/src/jstypedarray.h
index f666e52..4751d53 100644
--- a/src/third_party/mozjs/js/src/jstypedarray.h
+++ b/src/third_party/mozjs/js/src/jstypedarray.h
@@ -137,6 +137,24 @@
     static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
     static void restoreArrayBufferLists(ArrayBufferVector &vector);
 
+    bool hasStealableContents() const {
+        // Inline elements strictly adhere to the corresponding buffer.
+        if (!hasDynamicElements())
+            return false;
+
+        // asm.js buffer contents are transferred by copying, just like inline
+        // elements.
+        if (isAsmJSArrayBuffer())
+            return false;
+
+        // Neutered contents aren't transferrable because we want a neutered
+        // array's contents to be backed by zeroed memory equal in length to
+        // the original buffer contents.  Transferring these contents would
+        // allocate new ones based on the current byteLength, which is 0 for a
+        // neutered array -- not the original byteLength.
+        return !isNeutered();
+    }
+
     static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
                               uint8_t **data);
 
@@ -164,10 +182,17 @@
      */
     inline bool hasData() const;
 
-    inline bool isAsmJSArrayBuffer() const;
+    bool isAsmJSArrayBuffer() const {
+        return getElementsHeader()->isAsmJSArrayBuffer();
+    }
+
     static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
     static void neuterAsmJSArrayBuffer(ArrayBufferObject &buffer);
     static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
+
+    bool isNeutered() const {
+        return getElementsHeader()->isNeuteredBuffer();
+    }
 };
 
 /*
diff --git a/src/third_party/mozjs/js/src/jstypedarrayinlines.h b/src/third_party/mozjs/js/src/jstypedarrayinlines.h
index 5af70f5..f26e9cc 100644
--- a/src/third_party/mozjs/js/src/jstypedarrayinlines.h
+++ b/src/third_party/mozjs/js/src/jstypedarrayinlines.h
@@ -56,12 +56,6 @@
     return getClass() == &class_;
 }
 
-inline bool
-ArrayBufferObject::isAsmJSArrayBuffer() const
-{
-    return getElementsHeader()->isAsmJSArrayBuffer();
-}
-
 static inline int32_t
 ClampIntForUint8Array(int32_t x)
 {
diff --git a/src/third_party/mozjs/js/src/jsutil.cpp b/src/third_party/mozjs/js/src/jsutil.cpp
index bcab124..bd3e182 100644
--- a/src/third_party/mozjs/js/src/jsutil.cpp
+++ b/src/third_party/mozjs/js/src/jsutil.cpp
@@ -20,6 +20,10 @@
 
 #include "js/Utility.h"
 
+#ifdef USE_ZLIB
+#include "zlib.h"
+#endif
+
 using namespace js;
 
 using mozilla::PodArrayZero;
@@ -37,6 +41,32 @@
     js_free(addr);
 }
 
+class Compressor
+{
+    /* Number of bytes we should hand to zlib each compressMore() call. */
+    static const size_t CHUNKSIZE = 2048;
+    z_stream zs;
+    const unsigned char *inp;
+    size_t inplen;
+    size_t outbytes;
+
+  public:
+    enum Status {
+        MOREOUTPUT,
+        DONE,
+        CONTINUE,
+        OOM
+    };
+
+    Compressor(const unsigned char *inp, size_t inplen);
+    ~Compressor();
+    bool init();
+    void setOutput(unsigned char *out, size_t outlen);
+    size_t outWritten() const { return outbytes; }
+    /* Compress some of the input. Return true if it should be called again. */
+    Status compressMore();
+};
+
 Compressor::Compressor(const unsigned char *inp, size_t inplen)
     : inp(inp),
       inplen(inplen),
diff --git a/src/third_party/mozjs/js/src/jsutil.h b/src/third_party/mozjs/js/src/jsutil.h
index 64ebee5..9306a26 100644
--- a/src/third_party/mozjs/js/src/jsutil.h
+++ b/src/third_party/mozjs/js/src/jsutil.h
@@ -17,10 +17,6 @@
 
 #include "js/Utility.h"
 
-#ifdef USE_ZLIB
-#include "zlib.h"
-#endif
-
 /* Forward declarations. */
 struct JSContext;
 
@@ -265,31 +261,6 @@
 }
 
 #ifdef USE_ZLIB
-class Compressor
-{
-    /* Number of bytes we should hand to zlib each compressMore() call. */
-    static const size_t CHUNKSIZE = 2048;
-    z_stream zs;
-    const unsigned char *inp;
-    size_t inplen;
-    size_t outbytes;
-
-  public:
-    enum Status {
-        MOREOUTPUT,
-        DONE,
-        CONTINUE,
-        OOM
-    };
-
-    Compressor(const unsigned char *inp, size_t inplen);
-    ~Compressor();
-    bool init();
-    void setOutput(unsigned char *out, size_t outlen);
-    size_t outWritten() const { return outbytes; }
-    /* Compress some of the input. Return true if it should be called again. */
-    Status compressMore();
-};
 
 /*
  * Decompress a string. The caller must know the length of the output and
diff --git a/src/third_party/mozjs/js/src/vm/Interpreter.cpp b/src/third_party/mozjs/js/src/vm/Interpreter.cpp
index 9d53ec5..234c7b5 100644
--- a/src/third_party/mozjs/js/src/vm/Interpreter.cpp
+++ b/src/third_party/mozjs/js/src/vm/Interpreter.cpp
@@ -519,13 +519,18 @@
         /*
          * We must call the thisObject hook in case we are not called from the
          * interpreter, where a prior bytecode has computed an appropriate
-         * |this| already.
+         * |this| already.  But don't do that if fval is a DOM function.
          */
-        RootedObject thisObj(cx, &args.thisv().toObject());
-        JSObject *thisp = JSObject::thisObject(cx, thisObj);
-        if (!thisp)
-             return false;
-        args.setThis(ObjectValue(*thisp));
+       if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
+            !fval.toObject().as<JSFunction>().isNative() ||
+            !fval.toObject().as<JSFunction>().jitInfo())
+        {
+            RootedObject thisObj(cx, &args.thisv().toObject());
+            JSObject *thisp = JSObject::thisObject(cx, thisObj);
+            if (!thisp)
+                return false;
+            args.setThis(ObjectValue(*thisp));
+        }
     }
 
     if (!Invoke(cx, args))
diff --git a/src/third_party/mozjs/js/src/vm/ObjectImpl.cpp b/src/third_party/mozjs/js/src/vm/ObjectImpl.cpp
index b1ce275..98b97b1 100644
--- a/src/third_party/mozjs/js/src/vm/ObjectImpl.cpp
+++ b/src/third_party/mozjs/js/src/vm/ObjectImpl.cpp
@@ -182,8 +182,10 @@
 {
     static int throttle = -1;
     if (throttle < 0) {
+#if !defined(STARBOARD)
         if (const char *var = getenv("JS_CHECK_SHAPE_THROTTLE"))
             throttle = atoi(var);
+#endif
         if (throttle < 0)
             throttle = 0;
     }
diff --git a/src/third_party/mozjs/js/src/vm/ObjectImpl.h b/src/third_party/mozjs/js/src/vm/ObjectImpl.h
index 980f935..8eba5da 100644
--- a/src/third_party/mozjs/js/src/vm/ObjectImpl.h
+++ b/src/third_party/mozjs/js/src/vm/ObjectImpl.h
@@ -979,10 +979,11 @@
     enum Flags {
         CONVERT_DOUBLE_ELEMENTS = 0x1,
         ASMJS_ARRAY_BUFFER = 0x2,
+        NEUTERED_BUFFER = 0x4,
 
         // Present only if these elements correspond to an array with
         // non-writable length; never present for non-arrays.
-        NONWRITABLE_ARRAY_LENGTH = 0x4
+        NONWRITABLE_ARRAY_LENGTH = 0x8
     };
 
   private:
@@ -1036,6 +1037,12 @@
     void setIsAsmJSArrayBuffer() {
         flags |= ASMJS_ARRAY_BUFFER;
     }
+    bool isNeuteredBuffer() const {
+        return flags & NEUTERED_BUFFER;
+    }
+    void setIsNeuteredBuffer() {
+        flags |= NEUTERED_BUFFER;
+    }
     bool hasNonwritableArrayLength() const {
         return flags & NONWRITABLE_ARRAY_LENGTH;
     }
diff --git a/src/third_party/mozjs/js/src/vm/SelfHosting.cpp b/src/third_party/mozjs/js/src/vm/SelfHosting.cpp
index 87656bf..aecc895 100644
--- a/src/third_party/mozjs/js/src/vm/SelfHosting.cpp
+++ b/src/third_party/mozjs/js/src/vm/SelfHosting.cpp
@@ -26,6 +26,15 @@
 
 #include "selfhosted.out.h"
 
+#if defined(DEBUG) && defined(STARBOARD)
+// On Starboard platforms, DEBUG will get #undef'd when we #include zlib.h
+#define STARBOARD_DEBUG
+#endif
+
+#ifdef USE_ZLIB
+#include "zlib.h"
+#endif
+
 using namespace js;
 using namespace js::selfhosted;
 
@@ -186,7 +195,7 @@
 static JSBool
 intrinsic_AssertionFailed(JSContext *cx, unsigned argc, Value *vp)
 {
-#ifdef DEBUG
+#if defined(DEBUG) || defined(STARBOARD_DEBUG)
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() > 0) {
         // try to dump the informative string
@@ -304,7 +313,7 @@
     return true;
 }
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(STARBOARD_DEBUG)
 /*
  * Dump(val): Dumps a value for debugging, even in parallel mode.
  */
@@ -630,7 +639,7 @@
     JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
     JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(STARBOARD_DEBUG)
     JS_FN("Dump",                 intrinsic_Dump,                 1,0),
 #endif
 
diff --git a/src/third_party/mozjs/js/src/yarr/BumpPointerAllocator.h b/src/third_party/mozjs/js/src/yarr/BumpPointerAllocator.h
index 44fe538..0dcb1f8 100644
--- a/src/third_party/mozjs/js/src/yarr/BumpPointerAllocator.h
+++ b/src/third_party/mozjs/js/src/yarr/BumpPointerAllocator.h
@@ -34,7 +34,9 @@
 
 namespace WTF {
 
-#if WTF_CPU_SPARC
+#if defined(STARBOARD)
+#define MINIMUM_BUMP_POOL_SIZE SB_MEMORY_PAGE_SIZE
+#elif WTF_CPU_SPARC
 #define MINIMUM_BUMP_POOL_SIZE 0x2000
 #elif WTF_CPU_IA64
 #define MINIMUM_BUMP_POOL_SIZE 0x4000