Import Cobalt 6.16000
diff --git a/src/base/base.gypi b/src/base/base.gypi
index 79b9dd4..c1a5fff 100644
--- a/src/base/base.gypi
+++ b/src/base/base.gypi
@@ -589,11 +589,6 @@
               ['include', 'sys_string_conversions_linux.cc'],
             ],
           }],
-          [ 'OS=="lb_shell" and target_arch!="linux" and target_arch!="android"', {
-            'sources!': [
-              'string16.cc',  # wchar_t is 2-bytes wide, string16 == wstring here.
-            ],
-          }],
           [ 'OS=="lb_shell" and target_arch=="android"', {
             'sources/' : [
               ['exclude', 'message_pump_shell.cc'],
@@ -660,14 +655,6 @@
               # We use thread_checker_impl_atomic.cc instead.
               'threading/thread_checker_impl.cc',
             ],
-            'conditions': [
-              ['target_os!="linux" and target_os!="android"', {
-                'sources!': [
-                  # Since wchar_t is 2-bytes wide, string16 == wstring here.
-                  'string16.cc',
-                ],
-              }],
-            ],
           }],  # OS == "starboard"
           [ 'OS=="lb_shell" or OS=="starboard"', {
             'sources!': [
diff --git a/src/base/string16.cc b/src/base/string16.cc
index 930e09f..9c5acb7 100644
--- a/src/base/string16.cc
+++ b/src/base/string16.cc
@@ -4,14 +4,9 @@
 
 #include "base/string16.h"
 
-#if defined(WCHAR_T_IS_UTF16)
 
-#error This file should not be used on 2-byte wchar_t systems
-// If this winds up being needed on 2-byte wchar_t systems, either the
-// definitions below can be used, or the host system's wide character
-// functions like wmemcmp can be wrapped.
-
-#elif defined(WCHAR_T_IS_UTF32)
+// See discussion in string16.h: This is only needed on 32-bit wchar_t systems.
+#if defined(WCHAR_T_IS_UTF32)
 
 #include <ostream>
 
diff --git a/src/cobalt/audio/audio_destination_node.cc b/src/cobalt/audio/audio_destination_node.cc
index 59d80df..e0eda2b 100644
--- a/src/cobalt/audio/audio_destination_node.cc
+++ b/src/cobalt/audio/audio_destination_node.cc
@@ -38,8 +38,6 @@
     : AudioNode(context), max_channel_count_(kMaxChannelCount) {
   AudioLock::AutoLock lock(audio_lock());
 
-  audio_device_.reset(
-      new AudioDevice(static_cast<int>(channel_count(NULL)), this));
   AddInput(new AudioNodeInput(this));
 }
 
@@ -54,6 +52,15 @@
   RemoveAllInputs();
 }
 
+void AudioDestinationNode::OnInputNodeConnected() {
+  audio_lock()->AssertLocked();
+
+  if (!audio_device_) {
+    audio_device_.reset(
+        new AudioDevice(static_cast<int>(channel_count(NULL)), this));
+  }
+}
+
 void AudioDestinationNode::FillAudioBus(ShellAudioBus* audio_bus,
                                         bool* silence) {
   // This is called by Audio thread.
diff --git a/src/cobalt/audio/audio_destination_node.h b/src/cobalt/audio/audio_destination_node.h
index 14fab99..50bfe7e 100644
--- a/src/cobalt/audio/audio_destination_node.h
+++ b/src/cobalt/audio/audio_destination_node.h
@@ -48,7 +48,8 @@
   uint32 max_channel_count() const { return max_channel_count_; }
 
   // From AudioNode.
-  scoped_ptr<ShellAudioBus> PassAudioBusFromSource(int32, /*number_of_frames*/
+  void OnInputNodeConnected() OVERRIDE;
+  scoped_ptr<ShellAudioBus> PassAudioBusFromSource(int32 /*number_of_frames*/,
                                                    SampleType) OVERRIDE {
     NOTREACHED();
     return scoped_ptr<ShellAudioBus>();
diff --git a/src/cobalt/audio/audio_node.h b/src/cobalt/audio/audio_node.h
index 9564898..01a578d 100644
--- a/src/cobalt/audio/audio_node.h
+++ b/src/cobalt/audio/audio_node.h
@@ -111,6 +111,9 @@
   // Disconnects an AudioNode's output.
   void Disconnect(uint32 output, script::ExceptionState* exception_state);
 
+  // Called when a new input node has been connected.
+  virtual void OnInputNodeConnected() {}
+
   // TODO: Support wrapping ShellAudioBus into another ShellAudioBus.
   virtual scoped_ptr<ShellAudioBus> PassAudioBusFromSource(
       int32 number_of_frames, SampleType sample_type) = 0;
diff --git a/src/cobalt/audio/audio_node_input.cc b/src/cobalt/audio/audio_node_input.cc
index b0c8597..b7ac086 100644
--- a/src/cobalt/audio/audio_node_input.cc
+++ b/src/cobalt/audio/audio_node_input.cc
@@ -197,6 +197,7 @@
 
   output->AddInput(this);
   outputs_.insert(output);
+  owner_node_->OnInputNodeConnected();
 }
 
 void AudioNodeInput::Disconnect(AudioNodeOutput* output) {
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
index ff82636..9a486e9 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   AnonymousIndexedGetterInterface* impl =
@@ -109,7 +108,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
index a896d35..5431665 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   AnonymousNamedGetterInterface* impl =
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
index 8f883ff..0d132c4 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   AnonymousNamedIndexedGetterInterface* impl =
@@ -178,7 +177,6 @@
 
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   AnonymousNamedIndexedGetterInterface* impl =
@@ -201,7 +199,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index 1c88411..7c48cfc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   DerivedGetterSetterInterface* impl =
@@ -178,7 +177,6 @@
 
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   DerivedGetterSetterInterface* impl =
@@ -201,7 +199,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index b362b42..66f6497 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   IndexedGetterInterface* impl =
@@ -109,7 +108,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index 79fb735..51f1f54 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   NamedGetterInterface* impl =
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index e027bc0..2715fd9 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
 
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   NamedIndexedGetterInterface* impl =
@@ -178,7 +177,6 @@
 
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
   WrapperPrivate* wrapper_private =
       WrapperPrivate::GetFromObject(context, object);
   NamedIndexedGetterInterface* impl =
@@ -201,7 +199,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
index 2bd13c6..36e73dd 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
@@ -27,6 +27,7 @@
 #include "cobalt/script/logging_exception_state.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
 #include "cobalt/script/mozjs/mozjs_callback_interface.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 
@@ -40,6 +41,7 @@
 using cobalt::script::mozjs::FromJSValue;
 using cobalt::script::mozjs::GetCallableForCallbackInterface;
 using cobalt::script::mozjs::ToJSValue;
+using cobalt::script::mozjs::util::GetExceptionString;
 }  // namespace
 
 namespace cobalt {
@@ -90,7 +92,8 @@
       DCHECK(function);
       success = JS::Call(context_, this_value, function, kNumArguments, args,
                          return_value.address());
-      DLOG_IF(WARNING, !success) << "Exception in callback.";
+      DLOG_IF(WARNING, !success) << "Exception in callback: "
+                                 << GetExceptionString(context_);
       if (success) {
         LoggingExceptionState exception_state;
         FromJSValue(context_, return_value, 0, &exception_state,
diff --git a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
index 115f228..895e453 100644
--- a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
@@ -20,6 +20,7 @@
 #include "cobalt/script/logging_exception_state.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
 #include "cobalt/script/mozjs/mozjs_callback_interface.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 {% endblock includes %}
@@ -30,6 +31,7 @@
 using cobalt::script::mozjs::FromJSValue;
 using cobalt::script::mozjs::GetCallableForCallbackInterface;
 using cobalt::script::mozjs::ToJSValue;
+using cobalt::script::mozjs::util::GetExceptionString;
 {% endblock using_directives %}
 
 {% block implementation %}
@@ -90,7 +92,8 @@
       DCHECK(function);
       success = JS::Call(context_, this_value, function, kNumArguments, args,
                          return_value.address());
-      DLOG_IF(WARNING, !success) << "Exception in callback.";
+      DLOG_IF(WARNING, !success) << "Exception in callback: "
+                                 << GetExceptionString(context_);
 {% if overload.type != 'void' %}
       if (success) {
         LoggingExceptionState exception_state;
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 3307b67..b92a526 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -126,7 +126,6 @@
 {% if named_property_getter %}
 bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
                               const std::string& property_name) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
 {{ get_impl_class_instance(impl_class) }}
   return impl->CanQueryNamedProperty(property_name);
 }
@@ -215,7 +214,6 @@
 {% if indexed_property_getter %}
 bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
                               uint32_t index) {
-  TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
 {{ get_impl_class_instance(impl_class) }}
   return index < impl->length();
 }
@@ -232,7 +230,6 @@
 JSBool GetIndexedProperty(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
-  TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
   JS::RootedValue id_value(context);
   if (!JS_IdToValue(context, id, id_value.address())) {
     NOTREACHED();
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index ffded5e..470eda6 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/debug/trace_event.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/path_service.h"
@@ -62,7 +63,11 @@
 
 namespace {
 const int kStatUpdatePeriodMs = 1000;
+#if defined(COBALT_BUILD_TYPE_GOLD)
+const int kLiteStatUpdatePeriodMs = 1000;
+#else
 const int kLiteStatUpdatePeriodMs = 16;
+#endif
 
 const char kDefaultURL[] = "https://www.youtube.com/tv";
 
@@ -320,6 +325,8 @@
         FilePath(FILE_PATH_LITERAL("timed_trace.json")), trace_duration);
   }
 
+  TRACE_EVENT0("cobalt::browser", "Application::Application()");
+
   DCHECK(MessageLoop::current());
   DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
 
@@ -586,6 +593,7 @@
 }
 
 void Application::OnAccountEvent(const base::Event* event) {
+  TRACE_EVENT0("cobalt::browser", "Application::OnAccountEvent()");
   const account::AccountEvent* account_event =
       base::polymorphic_downcast<const account::AccountEvent*>(event);
   if (account_event->type() == account::AccountEvent::kSignedIn) {
@@ -600,6 +608,7 @@
 }
 
 void Application::OnNetworkEvent(const base::Event* event) {
+  TRACE_EVENT0("cobalt::browser", "Application::OnNetworkEvent()");
   DCHECK(network_event_thread_checker_.CalledOnValidThread());
   const network::NetworkEvent* network_event =
       base::polymorphic_downcast<const network::NetworkEvent*>(event);
@@ -620,6 +629,7 @@
 }
 
 void Application::OnApplicationEvent(const base::Event* event) {
+  TRACE_EVENT0("cobalt::browser", "Application::OnApplicationEvent()");
   DCHECK(application_event_thread_checker_.CalledOnValidThread());
   const system_window::ApplicationEvent* app_event =
       base::polymorphic_downcast<const system_window::ApplicationEvent*>(event);
@@ -651,6 +661,7 @@
 }
 
 void Application::OnDeepLinkEvent(const base::Event* event) {
+  TRACE_EVENT0("cobalt::browser", "Application::OnDeepLinkEvent()");
   const base::DeepLinkEvent* deep_link_event =
       base::polymorphic_downcast<const base::DeepLinkEvent*>(event);
   // TODO: Remove this when terminal application states are properly handled.
@@ -660,6 +671,7 @@
 }
 
 void Application::WebModuleRecreated() {
+  TRACE_EVENT0("cobalt::browser", "Application::WebModuleRecreated()");
 #if defined(ENABLE_WEBDRIVER)
   if (web_driver_module_) {
     web_driver_module_->OnWindowRecreated();
@@ -741,6 +753,7 @@
 }
 
 void Application::UpdatePeriodicStats() {
+  TRACE_EVENT0("cobalt::browser", "Application::UpdatePeriodicStats()");
 #if defined(__LB_SHELL__)
   bool memory_stats_updated = false;
 #if !defined(__LB_SHELL__FOR_RELEASE__)
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index e725572..9a730cc 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -168,11 +168,21 @@
       has_resumed_(true, false),
       will_quit_(false),
       suspended_(false) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::BrowserModule()");
   // All allocations for media will be tracked by "Media" memory scope.
   {
     TRACK_MEMORY_SCOPE("Media");
+    math::Size output_size = renderer_module_.render_target()->GetSize();
+    if (system_window->GetVideoPixelRatio() != 1.f) {
+      output_size.set_width(
+          static_cast<int>(static_cast<float>(output_size.width()) *
+                           system_window->GetVideoPixelRatio()));
+      output_size.set_height(
+          static_cast<int>(static_cast<float>(output_size.height()) *
+                           system_window->GetVideoPixelRatio()));
+    }
     media_module_ = (media::MediaModule::Create(
-        system_window, renderer_module_.render_target()->GetSize(),
+        system_window, output_size,
         renderer_module_.pipeline()->GetResourceProvider(),
         options.media_module_options));
   }
@@ -225,6 +235,7 @@
 }
 
 void BrowserModule::Navigate(const GURL& url) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::Navigate()");
   web_module_loaded_.Reset();
 
   // Always post this as a task in case this is being called from the WebModule.
@@ -233,6 +244,7 @@
 }
 
 void BrowserModule::Reload() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::Reload()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
   DCHECK(web_module_);
   web_module_->ExecuteJavascript(
@@ -241,6 +253,7 @@
 }
 
 void BrowserModule::NavigateInternal(const GURL& url) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::NavigateInternal()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
 
   // First try the registered handlers (e.g. for h5vcc://). If one of these
@@ -264,7 +277,7 @@
                        renderer_module_.pipeline()->GetResourceProvider(),
                        kLayoutMaxRefreshFrequencyInHz));
 
-#if defined(STARBOARD)
+#if defined(OS_STARBOARD)
 #if SB_HAS(1_CORE)
   // Wait until the splash screen is ready before loading the main web module.
   // This prevents starvation of the splash screen module and decoding of the
@@ -312,6 +325,7 @@
 }
 
 void BrowserModule::OnLoad() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::OnLoad()");
   // Repost to our own message loop if necessary. This also prevents
   // asynchonrous access to this object by |web_module_| during destruction.
   if (MessageLoop::current() != self_message_loop_) {
@@ -325,6 +339,7 @@
 }
 
 bool BrowserModule::WaitForLoad(const base::TimeDelta& timeout) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::WaitForLoad()");
   return web_module_loaded_.TimedWait(timeout);
 }
 
@@ -502,6 +517,7 @@
 }
 
 void BrowserModule::OnError(const GURL& url, const std::string& error) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::OnError()");
   LOG(ERROR) << error;
   std::string url_string = "h5vcc://network-failure";
 
@@ -512,6 +528,7 @@
 }
 
 bool BrowserModule::FilterKeyEvent(const dom::KeyboardEvent::Data& event) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::FilterKeyEvent()");
   // Check for hotkeys first. If it is a hotkey, no more processing is needed.
   if (!FilterKeyEventForHotkeys(event)) {
     return false;
@@ -577,7 +594,10 @@
   return false;
 }
 
-void BrowserModule::DestroySplashScreen() { splash_screen_.reset(NULL); }
+void BrowserModule::DestroySplashScreen() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::DestroySplashScreen()");
+  splash_screen_.reset(NULL);
+}
 
 #if defined(ENABLE_WEBDRIVER)
 scoped_ptr<webdriver::SessionDriver> BrowserModule::CreateSessionDriver(
@@ -649,6 +669,7 @@
 }
 
 void BrowserModule::Suspend() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::Suspend()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
   DCHECK(!suspended_);
 
@@ -691,6 +712,7 @@
 }
 
 void BrowserModule::Resume() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::Resume()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
   DCHECK(suspended_);
 
@@ -721,6 +743,8 @@
 
 #if defined(OS_STARBOARD)
 void BrowserModule::OnRendererSubmissionRasterized() {
+  TRACE_EVENT0("cobalt::browser",
+               "BrowserModule::OnRendererSubmissionRasterized()");
   if (!is_rendered_) {
     // Hide the system splash screen when the first render has completed.
     is_rendered_ = true;
diff --git a/src/cobalt/browser/stack_size_constants.h b/src/cobalt/browser/stack_size_constants.h
index d700f4b..c4e62ea 100644
--- a/src/cobalt/browser/stack_size_constants.h
+++ b/src/cobalt/browser/stack_size_constants.h
@@ -24,8 +24,11 @@
 #if defined(COBALT_BUILD_TYPE_DEBUG)
   // Non-optimized builds require a bigger stack size.
   const size_t kBaseStackSize = 2 * 1024 * 1024;
+#elif defined(COBALT_BUILD_TYPE_DEVEL)
+  // Devel builds require a slightly bigger stack size.
+  const size_t kBaseStackSize = 448 * 1024;
 #else
-  const size_t kBaseStackSize = 256 * 1024;
+  const size_t kBaseStackSize = 384 * 1024;
 #endif
   const size_t kWebModuleStackSize =
       kBaseStackSize + base::kAsanAdditionalStackSize;
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index af93505..defb344 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -46,11 +46,11 @@
 
 namespace {
 
-#if defined(COBALT_RELEASE)
+#if defined(COBALT_BUILD_TYPE_GOLD)
 const int kPollerPeriodMs = 2000;
-#else   // #if defined(COBALT_RELEASE)
+#else   // #if defined(COBALT_BUILD_TYPE_GOLD)
 const int kPollerPeriodMs = 20;
-#endif  // #if defined(COBALT_RELEASE)
+#endif  // #if defined(COBALT_BUILD_TYPE_GOLD)
 
 // The maximum number of element depth in the DOM tree. Elements at a level
 // deeper than this could be discarded, and will not be rendered.
@@ -147,7 +147,11 @@
   void CreateDebugServerIfNull();
 #endif  // ENABLE_DEBUG_CONSOLE
 
-  void Suspend();
+  // Suspension of the WebModule is a two-part process since a message loop
+  // gap is needed in order to give a chance to handle loader callbacks
+  // that were initiated from a loader thread.
+  void SuspendLoaders();
+  void FinishSuspend();
   void Resume(render_tree::ResourceProvider* resource_provider);
 
  private:
@@ -618,21 +622,20 @@
   }
 }
 
-void WebModule::Impl::Suspend() {
-  TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Suspend()");
-  DCHECK(resource_provider_);
+void WebModule::Impl::SuspendLoaders() {
+  TRACE_EVENT0("cobalt::browser", "WebModule::Impl::SuspendLoaders()");
 
   // Stop the generation of render trees.
   layout_manager_->Suspend();
 
-#if defined(ENABLE_DEBUG_CONSOLE)
-  // The debug overlay may be holding onto a render tree, clear that out.
-  debug_overlay_->ClearInput();
-#endif
-
   // Clear out the loader factory's resource provider, possibly aborting any
   // in-progress loads.
   loader_factory_->Suspend();
+}
+
+void WebModule::Impl::FinishSuspend() {
+  TRACE_EVENT0("cobalt::browser", "WebModule::Impl::FinishSuspend()");
+  DCHECK(resource_provider_);
 
   // Ensure the document is not holding onto any more image cached resources so
   // that they are eligible to be purged.
@@ -645,6 +648,11 @@
   image_cache_->Purge();
   remote_typeface_cache_->Purge();
 
+#if defined(ENABLE_DEBUG_CONSOLE)
+  // The debug overlay may be holding onto a render tree, clear that out.
+  debug_overlay_->ClearInput();
+#endif
+
   // Finally mark that we have no resource provider.
   resource_provider_ = NULL;
 }
@@ -877,16 +885,43 @@
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
 
 void WebModule::Suspend() {
-  message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebModule::Impl::Suspend, base::Unretained(impl_.get())));
+  TRACE_EVENT0("cobalt::browser", "WebModule::Suspend()");
 
-  base::WaitableEvent resource_provider_released(true, false);
-  message_loop()->PostTask(
-      FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
-                            base::Unretained(&resource_provider_released)));
+  // Suspend() must only be called by a thread external from the WebModule
+  // thread.
+  DCHECK_NE(MessageLoop::current(), message_loop());
 
-  resource_provider_released.Wait();
+  base::WaitableEvent task_finished(false /* automatic reset */,
+                                    false /* initially unsignaled */);
+
+  // Suspension of the WebModule is orchestrated here in two phases.
+  // 1) Send a signal to suspend WebModule loader activity and cancel any
+  //    in-progress loads.  Since loading may occur from any thread, this may
+  //    result in cancel/completion callbacks being posted to message_loop().
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&WebModule::Impl::SuspendLoaders,
+                                      base::Unretained(impl_.get())));
+
+  // Wait for the suspension task to complete before proceeding.
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&base::WaitableEvent::Signal,
+                                      base::Unretained(&task_finished)));
+  task_finished.Wait();
+
+  // 2) Now append to the task queue a task to complete the suspension process.
+  //    Between 1 and 2, tasks may have been registered to handle resource load
+  //    completion events, and so this FinishSuspend task will be executed after
+  //    the load completions are all resolved.
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&WebModule::Impl::FinishSuspend,
+                                      base::Unretained(impl_.get())));
+
+  // Wait for suspension to fully complete on the WebModule thread before
+  // continuing.
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&base::WaitableEvent::Signal,
+                                      base::Unretained(&task_finished)));
+  task_finished.Wait();
 }
 
 void WebModule::Resume(render_tree::ResourceProvider* resource_provider) {
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 1cb6aab..e0a264e 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-15306
\ No newline at end of file
+16000
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 314650b..53cc9b4 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -67,6 +67,13 @@
     # platform.
     'default_renderer_options_dependency%': '<(DEPTH)/cobalt/renderer/default_options_starboard.gyp:default_options',
 
+    # Allow throttling of the frame rate. This is expressed in terms of
+    # milliseconds and can be a floating point number. Keep in mind that
+    # swapping frames may take some additional processing time, so it may be
+    # better to specify a lower delay. For example, '33' instead of '33.33'
+    # for 30 Hz refresh.
+    'cobalt_minimum_frame_time_in_milliseconds%': '0',
+
     # The variables allow changing the target type on platforms where the
     # native code may require an additional packaging step (ex. Android).
     'gtest_target_type%': 'executable',
diff --git a/src/cobalt/css_parser/css_parser.gyp b/src/cobalt/css_parser/css_parser.gyp
index 185ee0b..32f9c0d 100644
--- a/src/cobalt/css_parser/css_parser.gyp
+++ b/src/cobalt/css_parser/css_parser.gyp
@@ -111,6 +111,7 @@
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
         '<(DEPTH)/cobalt/cssom/cssom.gyp:cssom',
+        '<(DEPTH)/nb/nb.gyp:nb',
         '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
         'css_grammar',
       ],
diff --git a/src/cobalt/css_parser/parser.cc b/src/cobalt/css_parser/parser.cc
index 25f4d35..cb4fb84 100644
--- a/src/cobalt/css_parser/parser.cc
+++ b/src/cobalt/css_parser/parser.cc
@@ -85,6 +85,7 @@
 #include "cobalt/cssom/unicode_range_value.h"
 #include "cobalt/cssom/universal_selector.h"
 #include "cobalt/cssom/url_value.h"
+#include "nb/memory_scope.h"
 
 namespace cobalt {
 namespace css_parser {
@@ -254,18 +255,21 @@
       into_declaration_data_(NULL) {}
 
 scoped_refptr<cssom::CSSStyleSheet> ParserImpl::ParseStyleSheet() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kStyleSheetEntryPointToken);
   return Parse() ? style_sheet_
                  : make_scoped_refptr(new cssom::CSSStyleSheet(css_parser_));
 }
 
 scoped_refptr<cssom::CSSRule> ParserImpl::ParseRule() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kRuleEntryPointToken);
   return Parse() ? rule_ : NULL;
 }
 
 scoped_refptr<cssom::CSSDeclaredStyleData>
 ParserImpl::ParseStyleDeclarationList() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kStyleDeclarationListEntryPointToken);
   return Parse() ? style_declaration_data_
                  : make_scoped_refptr(new cssom::CSSDeclaredStyleData());
@@ -273,6 +277,7 @@
 
 scoped_refptr<cssom::CSSFontFaceDeclarationData>
 ParserImpl::ParseFontFaceDeclarationList() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kFontFaceDeclarationListEntryPointToken);
   return Parse() ? font_face_declaration_data_
                  : make_scoped_refptr(new cssom::CSSFontFaceDeclarationData());
@@ -290,6 +295,7 @@
 
 scoped_refptr<cssom::PropertyValue> ParserImpl::ParsePropertyValue(
     const std::string& property_name) {
+  TRACK_MEMORY_SCOPE("CSS");
   Token property_name_token;
   bool is_property_name_known =
       scanner_.DetectPropertyNameToken(property_name, &property_name_token);
@@ -312,6 +318,7 @@
 void ParserImpl::ParsePropertyIntoDeclarationData(
     const std::string& property_name,
     cssom::CSSDeclarationData* declaration_data) {
+  TRACK_MEMORY_SCOPE("CSS");
   Token property_name_token;
   bool is_property_name_known =
       scanner_.DetectPropertyNameToken(property_name, &property_name_token);
@@ -340,11 +347,13 @@
 }
 
 scoped_refptr<cssom::MediaList> ParserImpl::ParseMediaList() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kMediaListEntryPointToken);
   return Parse() ? media_list_ : make_scoped_refptr(new cssom::MediaList());
 }
 
 scoped_refptr<cssom::MediaQuery> ParserImpl::ParseMediaQuery() {
+  TRACK_MEMORY_SCOPE("CSS");
   scanner_.PrependToken(kMediaQueryEntryPointToken);
   return Parse() ? media_query_ : make_scoped_refptr(new cssom::MediaQuery());
 }
@@ -364,6 +373,7 @@
 }
 
 bool ParserImpl::Parse() {
+  TRACK_MEMORY_SCOPE("CSS");
   // For more information on error codes
   // see http://www.gnu.org/software/bison/manual/html_node/Parser-Function.html
   TRACE_EVENT0("cobalt::css_parser", "ParseImpl::Parse");
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc
index 83bc8c0..9807b48 100644
--- a/src/cobalt/dom/media_source.cc
+++ b/src/cobalt/dom/media_source.cc
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
 #include "base/hash_tables.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
@@ -303,6 +304,8 @@
     SetReadyState(kReadyStateOpen);
   }
 
+  TRACE_EVENT1("media_stack", "MediaSource::Append()", "size", size);
+
   // If size is greater than kMaxAppendSize, we will append the data in multiple
   // small chunks with size less than or equal to kMaxAppendSize.  This can
   // avoid memory allocation spike as ChunkDemuxer may try to allocator memory
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 4426498..a04ced7 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -16,6 +16,7 @@
 
 #include "cobalt/layout/box.h"
 
+#include <algorithm>
 #include <limits>
 
 #include "base/logging.h"
@@ -907,7 +908,7 @@
                       style->opacity().get())->value();
 
   if (opacity < 1.0f) {
-    filter_node_builder->opacity_filter.emplace(opacity);
+    filter_node_builder->opacity_filter.emplace(std::max(0.0f, opacity));
   } else {
     // If opacity is 1, then no opacity filter should be applied, so the
     // source render tree should appear fully opaque.
@@ -1155,7 +1156,7 @@
     FilterNode::Builder filter_node_builder(border_node);
 
     if (opacity < 1.0f) {
-      filter_node_builder.opacity_filter = OpacityFilter(opacity);
+      filter_node_builder.opacity_filter.emplace(std::max(0.0f, opacity));
     }
 
     scoped_refptr<FilterNode> filter_node = new FilterNode(filter_node_builder);
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index 18dccb1..38adb86 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -189,6 +189,11 @@
     AnimationTimingAPILayoutTests, LayoutTest,
     ::testing::ValuesIn(EnumerateLayoutTests("animation-timing")));
 
+// Problematic test cases found through cluster-fuzz.
+INSTANTIATE_TEST_CASE_P(
+    ClusterFuzzLayoutTests, LayoutTest,
+    ::testing::ValuesIn(EnumerateLayoutTests("cluster-fuzz")));
+
 // Disable on Windows until network stack is implemented.
 #if !defined(COBALT_WIN)
 // Content Security Policy test cases.
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png
new file mode 100644
index 0000000..f1b767f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html
new file mode 100644
index 0000000..9f6ed1a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html
@@ -0,0 +1,17 @@
+cm/000000086.jpg" target="_blank"><img src="./picm/000000086.jpg" width="277" style="border: 0px solid ;"></a>
+<div class="blockImageCaption"><br>�s�d�k�F�i�O�W�V�j�W�V�W�|�Q�P�W�W�i���j<br>�e�`�w�F�i�O�W�V�j�W�V�W�|�Q�V�V�P</p>
+<!--  -->
+<!-- /blockText --></div>
+<!--  -->
+<!-- /blockText --></div>
+<!-- /block2column2 --></div>
+<br class="blockEdge">
+<!-- /CB0200_4 --></div>
+>
+<!--  -->
+
+<!--  --><div class="blockImage">
+<!--  -->
+ class="blockImageCaption"><small></small></div>
+>
+<!-- 
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt b/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt
new file mode 100644
index 0000000..12a4567
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt
@@ -0,0 +1 @@
+fuzz-222
\ No newline at end of file
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.css b/src/cobalt/loader/embedded_resources/splash_screen.css
index 7602576..3cba6e4 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.css
+++ b/src/cobalt/loader/embedded_resources/splash_screen.css
@@ -22,13 +22,12 @@
   width: 100%;
 }
 
-@keyframes loadwait {
-  0% {opacity: 0}
-  100% {opacity: 1}
-}
-
 #spinner {
-  animation: loadwait 2s steps(1, end);
+  /* The spinner starts with display set to none, and JavaScript will set this
+     to 'block' after some time has passed, if the splash screen is still
+     visible. */
+  display: none;
+
   height: 5.33em;
   margin: 0 auto;
   position: relative;
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.html b/src/cobalt/loader/embedded_resources/splash_screen.html
index 2a572ed..0e57e3b 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.html
+++ b/src/cobalt/loader/embedded_resources/splash_screen.html
@@ -3,8 +3,9 @@
 
 <head>
 <meta http-equiv="Content-Security-Policy" content="default-src 'none';
+    script-src h5vcc-embedded://*/splash_screen.js;
     style-src h5vcc-embedded://*/splash_screen.css;
-    img-src h5vcc-embedded://*/you_tube_logo.png">
+    img-src h5vcc-embedded://*/you_tube_logo.png;">
 <link rel="stylesheet" type="text/css" href="h5vcc-embedded://splash_screen.css">
 </head>
 
@@ -24,6 +25,8 @@
       <div class="dot" id="dot8"></div>
     </div>
   </div>
+  <script type="text/javascript" src="h5vcc-embedded://splash_screen.js">
+  </script>
 </body>
 
 </html>
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.js b/src/cobalt/loader/embedded_resources/splash_screen.js
new file mode 100644
index 0000000..0d30edc
--- /dev/null
+++ b/src/cobalt/loader/embedded_resources/splash_screen.js
@@ -0,0 +1,5 @@
+  // Enable the spinner after 3 seconds have passed.
+  window.setTimeout(function() {
+    var spinner = document.getElementById('spinner');
+    spinner.style.display = 'block';
+  }, 3000);
diff --git a/src/cobalt/loader/image/image_decoder.cc b/src/cobalt/loader/image/image_decoder.cc
index 6fcf6ec..5a55b9c 100644
--- a/src/cobalt/loader/image/image_decoder.cc
+++ b/src/cobalt/loader/image/image_decoder.cc
@@ -99,6 +99,7 @@
       failure_callback_(failure_callback),
       error_callback_(error_callback),
       state_(kWaitingForHeader) {
+  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::ImageDecoder()");
   signature_cache_.position = 0;
 
   if (!resource_provider_) {
@@ -109,6 +110,7 @@
 LoadResponseType ImageDecoder::OnResponseStarted(
     Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers) {
   UNREFERENCED_PARAMETER(fetcher);
+  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::OnResponseStarted()");
 
   if (state_ == kSuspended) {
     DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
@@ -202,6 +204,7 @@
 }
 
 bool ImageDecoder::Suspend() {
+  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::Suspend()");
   if (state_ == kDecoding) {
     DCHECK(decoder_);
     decoder_.reset();
@@ -213,6 +216,7 @@
 }
 
 void ImageDecoder::Resume(render_tree::ResourceProvider* resource_provider) {
+  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::Resume()");
   if (state_ != kSuspended) {
     DCHECK_EQ(resource_provider_, resource_provider);
     return;
@@ -227,6 +231,7 @@
 }
 
 void ImageDecoder::DecodeChunkInternal(const uint8* input_bytes, size_t size) {
+  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::DecodeChunkInternal()");
   switch (state_) {
     case kWaitingForHeader: {
       size_t consumed_size = 0;
@@ -263,6 +268,8 @@
 bool ImageDecoder::InitializeInternalDecoder(const uint8* input_bytes,
                                              size_t size,
                                              size_t* consumed_size) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "ImageDecoder::InitializeInternalDecoder()");
   const size_t index = signature_cache_.position;
   size_t fill_size = std::min(kLengthOfLongestSignature - index, size);
   memcpy(signature_cache_.data + index, input_bytes, fill_size);
diff --git a/src/cobalt/loader/image/image_decoder_starboard.cc b/src/cobalt/loader/image/image_decoder_starboard.cc
index 5a90442..1fdb7bf 100644
--- a/src/cobalt/loader/image/image_decoder_starboard.cc
+++ b/src/cobalt/loader/image/image_decoder_starboard.cc
@@ -38,17 +38,25 @@
       mime_type_(mime_type),
       format_(format),
       provider_(resource_provider->GetSbDecodeTargetProvider()),
-      target_(kSbDecodeTargetInvalid) {}
+      target_(kSbDecodeTargetInvalid) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "ImageDecoderStarboard::ImageDecoderStarboard()");
+}
 
 ImageDecoderStarboard::~ImageDecoderStarboard() {}
 
 size_t ImageDecoderStarboard::DecodeChunkInternal(const uint8* data,
                                                   size_t input_byte) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "ImageDecoderStarboard::DecodeChunkInternal()");
+
   buffer_.insert(buffer_.end(), data, data + input_byte);
   return input_byte;
 }
 
 void ImageDecoderStarboard::FinishInternal() {
+  TRACE_EVENT0("cobalt::loader::image",
+               "ImageDecoderStarboard::FinishInternal()");
   DCHECK(!buffer_.empty());
   DCHECK(SbImageIsDecodeSupported(mime_type_, format_));
   target_ =
diff --git a/src/cobalt/loader/image/jpeg_image_decoder.cc b/src/cobalt/loader/image/jpeg_image_decoder.cc
index 6fe1d91..29b99dc 100644
--- a/src/cobalt/loader/image/jpeg_image_decoder.cc
+++ b/src/cobalt/loader/image/jpeg_image_decoder.cc
@@ -84,6 +84,7 @@
 JPEGImageDecoder::JPEGImageDecoder(
     render_tree::ResourceProvider* resource_provider)
     : ImageDataDecoder(resource_provider) {
+  TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::JPEGImageDecoder()");
   memset(&info_, 0, sizeof(info_));
   memset(&source_manager_, 0, sizeof(source_manager_));
 
@@ -111,6 +112,8 @@
 
 size_t JPEGImageDecoder::DecodeChunkInternal(const uint8* data,
                                              size_t input_byte) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "JPEGImageDecoder::DecodeChunkInternal()");
   // |client_data| is available for use by application.
   jmp_buf jump_buffer;
   info_.client_data = &jump_buffer;
@@ -175,6 +178,7 @@
 }
 
 bool JPEGImageDecoder::ReadHeader() {
+  TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::ReadHeader()");
   if (jpeg_read_header(&info_, true) == JPEG_SUSPENDED) {
     // Since |jpeg_read_header| doesn't have enough data, go back to the state
     // before reading the header.
@@ -189,6 +193,7 @@
 }
 
 bool JPEGImageDecoder::StartDecompress() {
+  TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::StartDecompress()");
   // jpeg_has_multiple_scans() returns TRUE if the incoming image file has more
   // than one scan.
   info_.buffered_image = jpeg_has_multiple_scans(&info_);
@@ -215,6 +220,8 @@
 // TODO: support displaying the low resolution image while decoding
 // the progressive JPEG.
 bool JPEGImageDecoder::DecodeProgressiveJPEG() {
+  TRACE_EVENT0("cobalt::loader::image",
+               "JPEGImageDecoder::DecodeProgressiveJPEG()");
   int status;
   do {
     // |jpeg_consume_input| decodes the input data as it arrives.
@@ -291,6 +298,8 @@
 }
 
 bool JPEGImageDecoder::ReadLines() {
+  TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::ReadLines()");
+
   // Creation of 2-D sample arrays which is for one row.
   // See the comments in jmemmgr.c.
   JSAMPARRAY buffer = (*info_.mem->alloc_sarray)(
diff --git a/src/cobalt/loader/image/png_image_decoder.cc b/src/cobalt/loader/image/png_image_decoder.cc
index e87eeb9..b09e637 100644
--- a/src/cobalt/loader/image/png_image_decoder.cc
+++ b/src/cobalt/loader/image/png_image_decoder.cc
@@ -16,6 +16,7 @@
 
 #include "cobalt/loader/image/png_image_decoder.h"
 
+#include "base/debug/trace_event.h"
 #include "base/logging.h"
 
 namespace cobalt {
@@ -72,6 +73,8 @@
       info_(NULL),
       has_alpha_(false),
       interlace_buffer_(0) {
+  TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::PNGImageDecoder()");
+
   png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, DecodingFailed,
                                 DecodingWarning);
   info_ = png_create_info_struct(png_);
@@ -80,6 +83,8 @@
 }
 
 size_t PNGImageDecoder::DecodeChunkInternal(const uint8* data, size_t size) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "PNGImageDecoder::DecodeChunkInternal()");
   // int setjmp(jmp_buf env) saves the current environment (ths program state),
   // at some point of program execution, into a platform-specific data
   // structure (jmp_buf) that can be used at some later point of program
@@ -107,6 +112,7 @@
 }
 
 PNGImageDecoder::~PNGImageDecoder() {
+  TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::~PNGImageDecoder()");
   // Both are created at the same time. So they should be both zero
   // or both non-zero. Use && here to be safer.
   if (png_ && info_) {
@@ -127,6 +133,7 @@
 // static
 void PNGImageDecoder::HeaderAvailable(png_structp png, png_infop info) {
   UNREFERENCED_PARAMETER(info);
+  TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::~PNGImageDecoder()");
   PNGImageDecoder* decoder =
       static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png));
   decoder->HeaderAvailableCallback();
@@ -146,12 +153,16 @@
 // static
 void PNGImageDecoder::DecodeDone(png_structp png, png_infop info) {
   UNREFERENCED_PARAMETER(info);
+  TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::DecodeDone()");
+
   PNGImageDecoder* decoder =
       static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png));
   decoder->DecodeDoneCallback();
 }
 
 void PNGImageDecoder::HeaderAvailableCallback() {
+  TRACE_EVENT0("cobalt::loader::image",
+               "PNGImageDecoder::HeaderAvailableCallback()");
   DCHECK_EQ(state(), kWaitingForHeader);
 
   png_uint_32 width = png_get_image_width(png_, info_);
diff --git a/src/cobalt/loader/image/webp_image_decoder.cc b/src/cobalt/loader/image/webp_image_decoder.cc
index 53f24eb..cff8594 100644
--- a/src/cobalt/loader/image/webp_image_decoder.cc
+++ b/src/cobalt/loader/image/webp_image_decoder.cc
@@ -16,6 +16,7 @@
 
 #include "cobalt/loader/image/webp_image_decoder.h"
 
+#include "base/debug/trace_event.h"
 #include "base/logging.h"
 
 namespace cobalt {
@@ -25,6 +26,7 @@
 WEBPImageDecoder::WEBPImageDecoder(
     render_tree::ResourceProvider* resource_provider)
     : ImageDataDecoder(resource_provider), internal_decoder_(NULL) {
+  TRACE_EVENT0("cobalt::loader::image", "WEBPImageDecoder::WEBPImageDecoder()");
   // Initialize the configuration as empty.
   WebPInitDecoderConfig(&config_);
   // Skip the in-loop filtering.
@@ -37,10 +39,16 @@
   config_.options.no_enhancement = 1;
 }
 
-WEBPImageDecoder::~WEBPImageDecoder() { DeleteInternalDecoder(); }
+WEBPImageDecoder::~WEBPImageDecoder() {
+  TRACE_EVENT0("cobalt::loader::image",
+               "WEBPImageDecoder::~WEBPImageDecoder()");
+  DeleteInternalDecoder();
+}
 
 size_t WEBPImageDecoder::DecodeChunkInternal(const uint8* data,
                                              size_t input_byte) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "WEBPImageDecoder::DecodeChunkInternal()");
   const uint8* next_input_byte = data;
   size_t bytes_in_buffer = input_byte;
 
@@ -81,6 +89,7 @@
 
 bool WEBPImageDecoder::ReadHeader(const uint8* data, size_t size,
                                   bool* has_alpha) {
+  TRACE_EVENT0("cobalt::loader::image", "WEBPImageDecoder::ReadHeader()");
   // Retrieve features from the bitstream. The *features structure is filled
   // with information gathered from the bitstream.
   // Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
@@ -105,6 +114,8 @@
 }
 
 bool WEBPImageDecoder::CreateInternalDecoder(bool has_alpha) {
+  TRACE_EVENT0("cobalt::loader::image",
+               "WEBPImageDecoder::CreateInternalDecoder()");
   config_.output.colorspace = has_alpha ? MODE_rgbA : MODE_RGBA;
   config_.output.u.RGBA.stride = image_data()->GetDescriptor().pitch_in_bytes;
   config_.output.u.RGBA.size =
@@ -127,6 +138,8 @@
 }
 
 void WEBPImageDecoder::DeleteInternalDecoder() {
+  TRACE_EVENT0("cobalt::loader::image",
+               "WEBPImageDecoder::DeleteInternalDecoder()");
   if (internal_decoder_) {
     // Deletes the WebPIDecoder object and associated memory. Must always be
     // called if WebPIDecode succeeded.
diff --git a/src/cobalt/loader/sync_loader.cc b/src/cobalt/loader/sync_loader.cc
index 1d0d116..7ceff82 100644
--- a/src/cobalt/loader/sync_loader.cc
+++ b/src/cobalt/loader/sync_loader.cc
@@ -18,6 +18,7 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
 #include "base/synchronization/waitable_event.h"
 
 namespace cobalt {
@@ -117,6 +118,7 @@
     base::Callback<scoped_ptr<Fetcher>(Fetcher::Handler*)> fetcher_creator,
     base::Callback<scoped_ptr<Decoder>()> decoder_creator,
     base::Callback<void(const std::string&)> error_callback) {
+  TRACE_EVENT0("cobalt::loader", "LoadSynchronously()");
   DCHECK(message_loop);
   DCHECK(!error_callback.is_null());
 
diff --git a/src/cobalt/math/cubic_bezier.cc b/src/cobalt/math/cubic_bezier.cc
index 17c8368..51b5df0 100644
--- a/src/cobalt/math/cubic_bezier.cc
+++ b/src/cobalt/math/cubic_bezier.cc
@@ -66,8 +66,10 @@
   }
 
   // We should have terminated the above loop because we got close to x, not
-  // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
-  DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
+  // because we exceeded MAX_STEPS. Warn if this is not the case.
+  if (std::abs(eval_bezier(x1, x2, t) - x) > kBezierEpsilon) {
+    DLOG(WARNING) << "Notable error detected in bezier evaluation.";
+  }
 
   return t;
 }
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp
index 70c6929..ed7dc27 100644
--- a/src/cobalt/media/media.gyp
+++ b/src/cobalt/media/media.gyp
@@ -35,6 +35,7 @@
       'dependencies': [
         '<(DEPTH)/cobalt/network/network.gyp:network',
         '<(DEPTH)/media/media.gyp:media',
+        '<(DEPTH)/nb/nb.gyp:nb',
       ],
       'export_dependent_settings': [
         '<(DEPTH)/media/media.gyp:media',
@@ -46,9 +47,6 @@
             'shell_media_platform_<(sb_media_platform).cc',
             'shell_media_platform_<(sb_media_platform).h',
           ],
-          'dependencies': [
-            '<(DEPTH)/nb/nb.gyp:nb',
-          ],
         }],
         ['OS=="starboard" and sb_media_platform == "ps4"', {
           'sources': [
@@ -72,9 +70,6 @@
             'shell_media_platform_ps3.cc',
             'shell_media_platform_ps3.h',
           ],
-          'dependencies': [
-            '<(DEPTH)/nb/nb.gyp:nb',
-          ],
         }],
       ],
     },
diff --git a/src/cobalt/renderer/backend/egl/display.cc b/src/cobalt/renderer/backend/egl/display.cc
index dc325c7..c294168 100644
--- a/src/cobalt/renderer/backend/egl/display.cc
+++ b/src/cobalt/renderer/backend/egl/display.cc
@@ -54,6 +54,16 @@
   surface_ = eglCreateWindowSurface(display_, config_, native_window_, NULL);
   CHECK_EQ(EGL_SUCCESS, eglGetError());
 
+  // Configure the surface to preserve contents on swap.
+  EGLBoolean surface_attrib_set =
+      eglSurfaceAttrib(display_, surface_,
+                       EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+  // NOTE: Must check eglGetError() to clear any error flags and also check
+  // the return value of eglSurfaceAttrib since some implementations may not
+  // set the error condition.
+  content_preserved_on_swap_ =
+      eglGetError() == EGL_SUCCESS && surface_attrib_set == EGL_TRUE;
+
   // Query and cache information about the surface now that we have created it.
   EGLint egl_surface_width;
   EGLint egl_surface_height;
diff --git a/src/cobalt/renderer/backend/egl/graphics_system.cc b/src/cobalt/renderer/backend/egl/graphics_system.cc
index 16b5104..d8895bd 100644
--- a/src/cobalt/renderer/backend/egl/graphics_system.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_system.cc
@@ -64,23 +64,35 @@
 
   // Setup our configuration to support RGBA and compatibility with PBuffer
   // objects (for offscreen rendering).
-  EGLint const attribute_list[] = {EGL_RED_SIZE,
-                                   8,
-                                   EGL_GREEN_SIZE,
-                                   8,
-                                   EGL_BLUE_SIZE,
-                                   8,
-                                   EGL_ALPHA_SIZE,
-                                   8,
-                                   EGL_SURFACE_TYPE,
-                                   EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
-                                   EGL_BIND_TO_TEXTURE_RGBA,
-                                   EGL_TRUE,
-                                   EGL_NONE};
+  EGLint attribute_list[] = {EGL_SURFACE_TYPE,    // this must be first
+                             EGL_WINDOW_BIT | EGL_PBUFFER_BIT |
+                                EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
+                             EGL_RED_SIZE,
+                             8,
+                             EGL_GREEN_SIZE,
+                             8,
+                             EGL_BLUE_SIZE,
+                             8,
+                             EGL_ALPHA_SIZE,
+                             8,
+                             EGL_BIND_TO_TEXTURE_RGBA,
+                             EGL_TRUE,
+                             EGL_NONE};
+
+  // Try to allow preservation of the frame contents between swap calls --
+  // this will allow rendering of only parts of the frame that have changed.
+  DCHECK_EQ(EGL_SURFACE_TYPE, attribute_list[0]);
+  EGLint& surface_type_value = attribute_list[1];
 
   EGLint num_configs;
-  EGL_CALL(
-      eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs));
+  eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs);
+  if (eglGetError() != EGL_SUCCESS || num_configs == 0) {
+    // Swap buffer preservation may not be supported. Try to find a config
+    // without the feature.
+    surface_type_value &= ~EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+    EGL_CALL(
+        eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs));
+  }
   DCHECK_EQ(1, num_configs);
 
 #if defined(GLES3_SUPPORTED)
diff --git a/src/cobalt/renderer/backend/egl/render_target.h b/src/cobalt/renderer/backend/egl/render_target.h
index d88c385..9256372 100644
--- a/src/cobalt/renderer/backend/egl/render_target.h
+++ b/src/cobalt/renderer/backend/egl/render_target.h
@@ -27,7 +27,11 @@
 
 class RenderTargetEGL : public RenderTarget {
  public:
-  RenderTargetEGL() : swap_count_(0), has_been_made_current_(false) {}
+  RenderTargetEGL()
+      : swap_count_(0)
+      , has_been_made_current_(false)
+      , content_preserved_on_swap_(false)
+  {}
 
   // An EGLSurface is needed for the EGL function eglMakeCurrent() which
   // associates a render target with a rendering context.
@@ -40,6 +44,10 @@
 
   virtual bool IsWindowRenderTarget() const { return false; }
 
+  // Returns whether the render target contents are preserved after the
+  // target has been displayed via eglSwapBuffers().
+  bool IsContentPreservedOnSwap() const { return content_preserved_on_swap_; }
+
   int64 swap_count() { return swap_count_; }
   void increment_swap_count() { ++swap_count_; }
 
@@ -51,6 +59,7 @@
 
   int64 swap_count_;
   bool has_been_made_current_;
+  bool content_preserved_on_swap_;
 };
 
 }  // namespace backend
diff --git a/src/cobalt/renderer/frame_rate_throttler.cc b/src/cobalt/renderer/frame_rate_throttler.cc
new file mode 100644
index 0000000..20d662e
--- /dev/null
+++ b/src/cobalt/renderer/frame_rate_throttler.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.
+ */
+
+#include "cobalt/renderer/frame_rate_throttler.h"
+
+#include "base/threading/platform_thread.h"
+
+namespace cobalt {
+namespace renderer {
+
+void FrameRateThrottler::BeginInterval() {
+  if (COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS > 0) {
+    begin_time_ = base::TimeTicks::HighResNow();
+  }
+}
+
+void FrameRateThrottler::EndInterval() {
+  // Throttle presentation of new frames if a minimum frame time is specified.
+  if (COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS > 0) {
+    if (!begin_time_.is_null()) {
+      base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
+      base::TimeDelta wait_time =
+          base::TimeDelta::FromMillisecondsD(
+              COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS) -
+          elapsed;
+      if (wait_time > base::TimeDelta::FromMicroseconds(0)) {
+        base::PlatformThread::Sleep(wait_time);
+      }
+    }
+  }
+}
+
+}  // namespace renderer
+}  // namespace cobalt
diff --git a/src/cobalt/renderer/frame_rate_throttler.h b/src/cobalt/renderer/frame_rate_throttler.h
new file mode 100644
index 0000000..6af2be7
--- /dev/null
+++ b/src/cobalt/renderer/frame_rate_throttler.h
@@ -0,0 +1,44 @@
+/*
+ * 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_RENDERER_FRAME_RATE_THROTTLER_H_
+#define COBALT_RENDERER_FRAME_RATE_THROTTLER_H_
+
+#include "base/time.h"
+
+namespace cobalt {
+namespace renderer {
+
+// The FrameRateThrottler is used to enforce a minimum frame time. The
+// rasterizer should call the provided hooks just before and after submitting
+// a new frame. This can be used to throttle the frame rate (to 30 Hz for
+// example) when the presentation interval cannot be specified.
+class FrameRateThrottler {
+ public:
+  // To be called just after submitting a new frame.
+  void BeginInterval();
+
+  // To be called just before submitting a new frame.
+  void EndInterval();
+
+ private:
+  base::TimeTicks begin_time_;
+};
+
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // COBALT_RENDERER_FRAME_RATE_THROTTLER_H_
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 0056361..58d850b 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -74,9 +74,6 @@
       submission_disposal_thread_("Rasterizer Submission Disposal"),
       submit_even_if_render_tree_is_unchanged_(
           submit_even_if_render_tree_is_unchanged),
-      rasterize_current_tree_interval_timer_(
-          "Renderer.Rasterize.Interval",
-          kRasterizeCurrentTreeTimerTimeIntervalInMs),
       rasterize_current_tree_timer_("Renderer.Rasterize.Duration",
                                     kRasterizeCurrentTreeTimerTimeIntervalInMs)
 #if defined(ENABLE_DEBUG_CONSOLE)
@@ -239,7 +236,6 @@
     return;
   }
 
-  rasterize_current_tree_interval_timer_.Start(now);
   rasterize_current_tree_timer_.Start(now);
 
   // Rasterize the last submitted render tree.
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 3b96cc3..d3a2e96 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -185,10 +185,8 @@
   // The submission time used during the last render tree render.
   base::optional<base::TimeDelta> last_render_time_;
 
-  // Timers for tracking how frequently |RasterizeCurrentTree| is called and
-  // the amount of time spent in |RasterizeCurrentTree| each call.
-  base::CValTimeIntervalTimer<base::CValPublic>
-      rasterize_current_tree_interval_timer_;
+  // Timer tracking the amount of time spent in |RasterizeCurrentTree| each
+  // call.
   base::CValTimeIntervalTimer<base::CValPublic> rasterize_current_tree_timer_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
index bcb25db..5e65c9c 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
@@ -117,7 +117,7 @@
       surface_map_.erase(found);
       surface_map_.insert(to_insert);
 
-      cache_frame_usage_ += found->second.GetEstimatedMemoryUsage();
+      cache_frame_usage_ += to_insert.second.GetEstimatedMemoryUsage();
 
       return to_insert.second;
     }
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index 7c9304e..cfca7ab 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -26,6 +26,7 @@
 #include "cobalt/render_tree/resource_provider_stub.h"
 #include "cobalt/renderer/backend/blitter/graphics_context.h"
 #include "cobalt/renderer/backend/blitter/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
 #include "cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h"
 #include "cobalt/renderer/rasterizer/blitter/render_state.h"
 #include "cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h"
@@ -80,6 +81,8 @@
 
   CachedSoftwareRasterizer software_surface_cache_;
 
+  FrameRateThrottler frame_rate_throttler_;
+
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Debug command to toggle cache highlights to help visualize which nodes
   // are being cached.
@@ -219,7 +222,9 @@
                                 SbBlitterMakeRect(0, 0, width, height),
                                 SbBlitterMakeRect(0, 0, width, height)));
   CHECK(SbBlitterFlushContext(context));
+  frame_rate_throttler_.EndInterval();
   render_target_blitter->Flip();
+  frame_rate_throttler_.BeginInterval();
 
   ++submit_count_;
 }
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
index 8fc3821..47dcf43 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -17,6 +17,7 @@
 #include "cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h"
 
 #include "base/bind.h"
+#include "base/debug/trace_event.h"
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/math/matrix3_f.h"
 #include "cobalt/math/rect.h"
@@ -33,6 +34,17 @@
 
 #if SB_HAS(BLITTER)
 
+// This define exists so that developers can quickly toggle it temporarily and
+// obtain trace results for the render tree visit process here.  In general
+// though it slows down tracing too much to leave it enabled.
+#define ENABLE_RENDER_TREE_VISITOR_TRACING 0
+
+#if ENABLE_RENDER_TREE_VISITOR_TRACING
+#define TRACE_EVENT0_IF_ENABLED(x) TRACE_EVENT0("cobalt::renderer", x)
+#else
+#define TRACE_EVENT0_IF_ENABLED(x)
+#endif
+
 namespace cobalt {
 namespace renderer {
 namespace rasterizer {
@@ -78,6 +90,8 @@
 
 void RenderTreeNodeVisitor::Visit(
     render_tree::CompositionNode* composition_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(CompositionNode)");
+
   const render_tree::CompositionNode::Children& children =
       composition_node->data().children();
 
@@ -119,6 +133,8 @@
 }  // namespace
 
 void RenderTreeNodeVisitor::Visit(render_tree::FilterNode* filter_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(FilterNode)");
+
   if (filter_node->data().blur_filter) {
     // The Starboard Blitter API does not support blur filters, so we fallback
     // to software for this.
@@ -193,6 +209,8 @@
 }
 
 void RenderTreeNodeVisitor::Visit(render_tree::ImageNode* image_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(ImageNode)");
+
   // All Blitter API images derive from skia::Image (so that they can be
   // compatible with the Skia software renderer), so we start here by casting
   // to skia::Image.
@@ -252,6 +270,8 @@
 
 void RenderTreeNodeVisitor::Visit(
     render_tree::MatrixTransformNode* matrix_transform_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(MatrixTransformNode)");
+
   const Matrix3F& transform = matrix_transform_node->data().transform;
 
   if (transform.Get(1, 0) != 0 || transform.Get(0, 1) != 0 ||
@@ -276,20 +296,16 @@
 
 void RenderTreeNodeVisitor::Visit(
     render_tree::PunchThroughVideoNode* punch_through_video_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(PunchThroughVideoNode)");
+
   SbBlitterRect blitter_rect =
       RectFToBlitterRect(render_state_.transform.TransformRect(
           punch_through_video_node->data().rect));
 
-  if (punch_through_video_node->data().set_bounds_cb.is_null()) {
-    return;
-  }
-  bool render_punch_through =
-      punch_through_video_node->data().set_bounds_cb.Run(
-          math::Rect(blitter_rect.x, blitter_rect.y, blitter_rect.width,
-                     blitter_rect.height));
-  if (!render_punch_through) {
-    return;
-  }
+  punch_through_video_node->data().set_bounds_cb.Run(
+      math::Rect(blitter_rect.x, blitter_rect.y, blitter_rect.width,
+                 blitter_rect.height));
+
   SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
   SbBlitterSetBlending(context_, false);
   SbBlitterFillRect(context_, blitter_rect);
@@ -355,6 +371,8 @@
 }  // namespace
 
 void RenderTreeNodeVisitor::Visit(render_tree::RectNode* rect_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(RectNode)");
+
   if (rect_node->data().rounded_corners) {
     // We can't render rounded corners through the Blitter API.
     RenderWithSoftwareRenderer(rect_node);
@@ -436,15 +454,20 @@
 
 void RenderTreeNodeVisitor::Visit(
     render_tree::RectShadowNode* rect_shadow_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(RectShadowNode)");
+
   RenderWithSoftwareRenderer(rect_shadow_node);
 }
 
 void RenderTreeNodeVisitor::Visit(render_tree::TextNode* text_node) {
+  TRACE_EVENT0_IF_ENABLED("Visit(TextNode)");
+
   RenderWithSoftwareRenderer(text_node);
 }
 
 void RenderTreeNodeVisitor::RenderWithSoftwareRenderer(
     render_tree::Node* node) {
+  TRACE_EVENT0("cobalt::renderer", "RenderWithSoftwareRenderer()");
   CachedSoftwareRasterizer::SurfaceReference software_surface_reference(
       software_surface_cache_, node, render_state_.transform);
   CachedSoftwareRasterizer::Surface software_surface =
@@ -483,6 +506,7 @@
   } else  // NOLINT(readability/braces)
 #endif    // defined(ENABLE_DEBUG_CONSOLE)
   {
+    TRACE_EVENT0("cobalt::renderer", "SbBlitterBlitRectToRect()");
     SbBlitterBlitRectToRect(
         context_, software_surface.surface,
         SbBlitterMakeRect(
@@ -494,6 +518,8 @@
 
 scoped_ptr<RenderTreeNodeVisitor::OffscreenRender>
 RenderTreeNodeVisitor::RenderToOffscreenSurface(render_tree::Node* node) {
+  TRACE_EVENT0_IF_ENABLED("RenderToOffscreenSurface()");
+
   common::OffscreenRenderCoordinateMapping coord_mapping =
       common::GetOffscreenRenderCoordinateMapping(
           node->GetBounds(), render_state_.transform.ToMatrix(),
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
index 6622fbc..f96d931 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
@@ -95,7 +95,9 @@
 
   SbBlitterDestroySurface(surface);
 
+  frame_rate_throttler_.EndInterval();
   render_target_blitter->Flip();
+  frame_rate_throttler_.BeginInterval();
 }
 
 render_tree::ResourceProvider* SoftwareRasterizer::GetResourceProvider() {
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
index 646f3c4..04aa2ac 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
@@ -26,6 +26,7 @@
 #include "cobalt/renderer/backend/blitter/graphics_context.h"
 #include "cobalt/renderer/backend/graphics_context.h"
 #include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
 #include "cobalt/renderer/rasterizer/rasterizer.h"
 #include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
 
@@ -51,6 +52,7 @@
  private:
   backend::GraphicsContextBlitter* context_;
   skia::SoftwareRasterizer skia_rasterizer_;
+  FrameRateThrottler frame_rate_throttler_;
 };
 
 }  // namespace blitter
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
index 97fcc63..8798b04 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
@@ -92,7 +92,9 @@
       context_, render_target_egl);
 
   context_->Blit(output_texture->gl_handle(), 0, 0, width, height);
+  frame_rate_throttler_.EndInterval();
   context_->SwapBuffers(render_target_egl);
+  frame_rate_throttler_.BeginInterval();
 }
 
 render_tree::ResourceProvider* SoftwareRasterizer::GetResourceProvider() {
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
index 8ae5e84..479ce7e 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
@@ -21,6 +21,7 @@
 #include "cobalt/render_tree/resource_provider.h"
 #include "cobalt/renderer/backend/graphics_context.h"
 #include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
 #include "cobalt/renderer/rasterizer/rasterizer.h"
 #include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
 
@@ -51,6 +52,7 @@
  private:
   backend::GraphicsContextEGL* context_;
   skia::SoftwareRasterizer skia_rasterizer_;
+  FrameRateThrottler frame_rate_throttler_;
 };
 
 }  // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 2fd11a4..68e4c7a 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -2802,8 +2802,8 @@
       RoundedCorners(50, 50)));
 }
 
-// If SetBoundsCB() returns false, the PunchThroughVideoNode should have no
-// effect.
+// PunchThroughVideoNode should trigger the painting of a solid rectangle with
+// RGBA(0, 0, 0, 0) regardless of whether SetBoundsCB returns true or false.
 TEST_F(PixelTest, PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse) {
   CompositionNode::Builder builder;
   builder.AddChild(new RectNode(RectF(25, 25, 150, 150),
@@ -2816,8 +2816,6 @@
   TestTree(new CompositionNode(builder.Pass()));
 }
 
-// If SetBoundsCB() returns true, the PunchThroughVideoNode should trigger the
-// painting of a solid rectangle with RGBA(0, 0, 0, 0).
 TEST_F(PixelTest, PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsTrue) {
   CompositionNode::Builder builder;
   builder.AddChild(new RectNode(RectF(25, 25, 150, 150),
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index c3e2a0d..2ea8e6e 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -20,6 +20,8 @@
 
 #include "base/debug/trace_event.h"
 #include "cobalt/renderer/backend/egl/graphics_context.h"
+#include "cobalt/renderer/backend/egl/graphics_system.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
 #include "cobalt/renderer/rasterizer/common/surface_cache.h"
 #include "cobalt/renderer/rasterizer/skia/cobalt_skia_type_conversions.h"
 #include "cobalt/renderer/rasterizer/skia/hardware_resource_provider.h"
@@ -85,6 +87,8 @@
 
   base::optional<SurfaceCacheDelegate> surface_cache_delegate_;
   base::optional<common::SurfaceCache> surface_cache_;
+
+  FrameRateThrottler frame_rate_throttler_;
 };
 
 namespace {
@@ -231,6 +235,13 @@
 
   if (options.flags & Rasterizer::kSubmitFlags_Clear) {
     canvas->clear(SkColorSetARGB(0, 0, 0, 0));
+  } else if (options.dirty) {
+    // Only a portion of the display is dirty. Reuse the previous frame
+    // if possible.
+    if (render_target_egl->IsContentPreservedOnSwap() &&
+        render_target_egl->swap_count() >= 3) {
+      canvas->clipRect(CobaltRectFToSkiaRect(*options.dirty));
+    }
   }
 
   {
@@ -254,7 +265,9 @@
     canvas->flush();
   }
 
+  frame_rate_throttler_.EndInterval();
   graphics_context_->SwapBuffers(render_target_egl);
+  frame_rate_throttler_.BeginInterval();
   canvas->restore();
 }
 
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index a17b893..195b6fb 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -177,14 +177,13 @@
   SkFontMgr_Cobalt* font_manager =
       base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get());
 
-  SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name);
-  SkiaTypeface* skia_type_face = NULL;
+  SkTypeface* typeface = font_manager->matchFaceName(font_face_name);
   if (typeface != NULL) {
     SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface);
-    skia_type_face = new SkiaTypeface(typeface);
+    return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
   }
 
-  return scoped_refptr<render_tree::Typeface>(skia_type_face);
+  return NULL;
 }
 
 scoped_refptr<render_tree::Typeface>
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 9e2116d..fd5dfd9 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -737,18 +737,11 @@
   SkRect sk_rect_transformed;
   total_matrix.mapRect(&sk_rect_transformed, sk_rect);
 
-  if (punch_through_video_node->data().set_bounds_cb.is_null()) {
-    return;
-  }
-  bool render_punch_through =
-      punch_through_video_node->data().set_bounds_cb.Run(
-          math::Rect(static_cast<int>(sk_rect_transformed.x()),
-                     static_cast<int>(sk_rect_transformed.y()),
-                     static_cast<int>(sk_rect_transformed.width()),
-                     static_cast<int>(sk_rect_transformed.height())));
-  if (!render_punch_through) {
-    return;
-  }
+  punch_through_video_node->data().set_bounds_cb.Run(
+      math::Rect(static_cast<int>(sk_rect_transformed.x()),
+                 static_cast<int>(sk_rect_transformed.y()),
+                 static_cast<int>(sk_rect_transformed.width()),
+                 static_cast<int>(sk_rect_transformed.height())));
 
   SkPaint paint;
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
index 63f1e67..4111f1b 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
@@ -300,7 +300,7 @@
         break;
       case 15:
         if (strncmp("postscript_name", name, 15) == 0) {
-          file->postcript_name = value;
+          file->postscript_name = value;
           seen_attributes_flag |= kSeenFontPostscriptName;
           continue;
         }
@@ -341,7 +341,7 @@
   DCHECK_EQ(seen_attributes_flag, kSeenFontFullName | kSeenFontPostscriptName |
                                       kSeenWeight | kSeenStyle);
   DCHECK(!file->full_font_name.isEmpty());
-  DCHECK(!file->postcript_name.isEmpty());
+  DCHECK(!file->postscript_name.isEmpty());
 }
 
 FontFamily* FindFamily(FamilyData* family_data, const char* family_name) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index 5ab5536..6c9aa9d 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -25,6 +25,7 @@
 
 #include "base/at_exit.h"
 #include "base/bind.h"
+#include "base/debug/trace_event.h"
 #include "base/lazy_instance.h"
 #include "base/memory/singleton.h"
 #include "cobalt/base/c_val.h"
@@ -48,6 +49,8 @@
 
 // NOTE: It is the responsibility of the caller to call Unref() on the SkData.
 SkData* NewDataFromFile(const SkString& file_path) {
+  TRACE_EVENT1("cobalt::renderer", "SkFontMgr_cobalt::NewDataFromFile()",
+               "file_path", TRACE_STR_COPY(file_path.c_str()));
   LOG(INFO) << "Loading font file: " << file_path.c_str();
 
   SkAutoTUnref<SkStream> file_stream(SkStream::NewFromFile(file_path.c_str()));
@@ -159,6 +162,7 @@
   }
 
   virtual SkStream* onOpenStream(int* ttc_index) const SK_OVERRIDE {
+    TRACE_EVENT0("cobalt::renderer", "SkTypeface_CobaltSystem::onOpenStream()");
     *ttc_index = index_;
 
     // Scope the initial mutex lock.
@@ -175,6 +179,7 @@
       }
     }
 
+    TRACE_EVENT0("cobalt::renderer", "Load data from file");
     // This is where the bulk of the time will be spent, so load the font data
     // outside of a mutex lock.
     SkAutoTUnref<SkData> data(NewDataFromFile(path_name_));
@@ -237,6 +242,8 @@
       language_(family.language),
       page_ranges_(family.page_ranges),
       is_character_map_generated_(false) {
+  TRACE_EVENT0("cobalt::renderer",
+               "SkFontStyleSet_Cobalt::SkFontStyleSet_Cobalt()");
   DCHECK(manager_owned_mutex_);
 
   if (family.names.count() == 0) {
@@ -269,12 +276,12 @@
 
     std::string full_font_name(font_file.full_font_name.c_str(),
                                font_file.full_font_name.size());
-    std::string postcript_name(font_file.postcript_name.c_str(),
-                               font_file.postcript_name.size());
+    std::string postscript_name(font_file.postscript_name.c_str(),
+                                font_file.postscript_name.size());
 
     styles_.push_back().reset(SkNEW_ARGS(
         SkFontStyleSetEntry_Cobalt,
-        (path_name, font_file.index, style, full_font_name, postcript_name)));
+        (path_name, font_file.index, style, full_font_name, postscript_name)));
   }
 }
 
@@ -306,34 +313,57 @@
 
 SkTypeface* SkFontStyleSet_Cobalt::MatchStyleWithoutLocking(
     const SkFontStyle& pattern) {
-  while (styles_.count() > 0) {
-    int style_index = GetClosestStyleIndex(pattern);
-    SkFontStyleSetEntry_Cobalt* style = styles_[style_index];
-    if (style->typeface == NULL) {
-      CreateSystemTypeface(style);
-
-      // Check to see if the typeface is still NULL. If this is the case, then
-      // the style can't be created. Remove it from the array.
-      if (style->typeface == NULL) {
-        styles_[style_index].swap(&styles_.back());
-        styles_.pop_back();
-        continue;
-      }
-    }
-
-    return SkRef(style->typeface.get());
+  SkTypeface* typeface = NULL;
+  while (typeface == NULL && styles_.count() > 0) {
+    typeface = TryRetrieveTypefaceAndRemoveStyleOnFailure(
+        GetClosestStyleIndex(pattern));
   }
+  return typeface;
+}
 
+SkTypeface* SkFontStyleSet_Cobalt::MatchFullFontName(const std::string& name) {
+  for (int i = 0; i < styles_.count(); ++i) {
+    if (styles_[i]->full_font_name == name) {
+      return TryRetrieveTypefaceAndRemoveStyleOnFailure(i);
+    }
+  }
   return NULL;
 }
 
+SkTypeface* SkFontStyleSet_Cobalt::MatchFontPostScriptName(
+    const std::string& name) {
+  for (int i = 0; i < styles_.count(); ++i) {
+    if (styles_[i]->font_postscript_name == name) {
+      return TryRetrieveTypefaceAndRemoveStyleOnFailure(i);
+    }
+  }
+  return NULL;
+}
+
+SkTypeface* SkFontStyleSet_Cobalt::TryRetrieveTypefaceAndRemoveStyleOnFailure(
+    int style_index) {
+  DCHECK(style_index >= 0 && style_index < styles_.count());
+  SkFontStyleSetEntry_Cobalt* style = styles_[style_index];
+  // If the typeface doesn't already exist, then attempt to create it.
+  if (style->typeface == NULL) {
+    CreateSystemTypeface(style);
+    // If the creation attempt failed and the typeface is still NULL, then
+    // remove the entry from the set's styles.
+    if (style->typeface == NULL) {
+      styles_[style_index].swap(&styles_.back());
+      styles_.pop_back();
+      return NULL;
+    }
+  }
+  return SkRef(style->typeface.get());
+}
+
 bool SkFontStyleSet_Cobalt::ContainsTypeface(const SkTypeface* typeface) {
   for (int i = 0; i < styles_.count(); ++i) {
     if (styles_[i]->typeface == typeface) {
       return true;
     }
   }
-
   return false;
 }
 
@@ -371,6 +401,9 @@
   // The character map is lazily generated. Generate it now if it isn't already
   // generated.
   if (!is_character_map_generated_) {
+    TRACE_EVENT0("cobalt::renderer",
+                 "SkFontStyleSet_Cobalt::ContainsCharacter() and "
+                 "!is_character_map_generated_");
     // Attempt to load the closest font style from the set. If it fails to load,
     // it will be removed from the set and, as long as font styles remain in the
     // set, the logic will be attempted again.
@@ -422,6 +455,7 @@
   if (is_character_map_generated_) {
     return;
   }
+  TRACE_EVENT0("cobalt::renderer", "GenerateCharacterMapFromData()");
 
   FT_Library freetype_lib;
   if (FT_Init_FreeType(&freetype_lib) != 0) {
@@ -476,6 +510,8 @@
 
 void SkFontStyleSet_Cobalt::CreateSystemTypeface(
     SkFontStyleSetEntry_Cobalt* style_entry) {
+  TRACE_EVENT0("cobalt::renderer",
+               "SkFontStyleSet_Cobalt::CreateSystemTypeface()");
   SkAutoTUnref<SkData> font_data(NewDataFromFile(style_entry->font_file_path));
   if (font_data != NULL) {
     CreateSystemTypefaceFromData(style_entry, font_data);
@@ -484,6 +520,8 @@
 
 void SkFontStyleSet_Cobalt::CreateSystemTypefaceFromData(
     SkFontStyleSetEntry_Cobalt* style_entry, SkData* data) {
+  TRACE_EVENT0("cobalt::renderer",
+               "SkFontStyleSet_Cobalt::CreateSystemTypefaceFromData()");
   DCHECK(!style_entry->typeface);
 
   // Since the font data is available, generate the character map if this is a
@@ -582,13 +620,17 @@
     const char* directory, const SkTArray<SkString, true>& default_fonts)
     : default_family_(NULL),
       last_font_cache_purge_time_(base::TimeTicks::Now()) {
+  TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::SkFontMgr_Cobalt()");
   // Ensure that both the CValManager and SkFontMgrCVals are initialized. The
   // CValManager is created first as it must outlast the SkFontMgrCVals.
   base::CValManager::GetInstance();
   SkFontMgrCVals::GetInstance();
 
   SkTDArray<FontFamily*> font_families;
-  SkFontConfigParser::GetFontFamilies(directory, &font_families);
+  {
+    TRACE_EVENT0("cobalt::renderer", "SkFontConfigParser::GetFontFamilies()");
+    SkFontConfigParser::GetFontFamilies(directory, &font_families);
+  }
   BuildNameToFamilyMap(directory, &font_families);
   font_families.deleteAll();
 
@@ -610,6 +652,41 @@
   }
 }
 
+SkTypeface* SkFontMgr_Cobalt::matchFaceName(const std::string& font_face_name) {
+  if (font_face_name.empty()) {
+    return NULL;
+  }
+
+  // Lock the style sets mutex prior to accessing them.
+  SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
+
+  // Prioritize looking up the postscript name first since some of our client
+  // applications prefer this method to specify face names.
+  for (int i = 0; i <= 1; ++i) {
+    NameToStyleSetMap& name_to_style_set_map =
+        i == 0 ? font_postscript_name_to_style_set_map_
+               : full_font_name_to_style_set_map_;
+
+    NameToStyleSetMap::iterator style_set_iterator =
+        name_to_style_set_map.find(font_face_name);
+    if (style_set_iterator != name_to_style_set_map.end()) {
+      SkFontStyleSet_Cobalt* style_set = style_set_iterator->second;
+      SkTypeface* typeface =
+          i == 0 ? style_set->MatchFontPostScriptName(font_face_name)
+                 : style_set->MatchFullFontName(font_face_name);
+      if (typeface != NULL) {
+        return typeface;
+      } else {
+        // If no typeface was successfully created then remove the entry from
+        // the map. It won't provide a successful result in subsequent calls
+        // either.
+        name_to_style_set_map.erase(style_set_iterator);
+      }
+    }
+  }
+  return NULL;
+}
+
 int SkFontMgr_Cobalt::onCountFamilies() const { return family_names_.count(); }
 
 void SkFontMgr_Cobalt::onGetFamilyName(int index, SkString* family_name) const {
@@ -626,7 +703,7 @@
     return NULL;
   }
 
-  NameToFamilyMap::const_iterator family_iterator =
+  NameToStyleSetMap::const_iterator family_iterator =
       name_to_family_map_.find(family_names_[index].c_str());
   if (family_iterator != name_to_family_map_.end()) {
     return SkRef(family_iterator->second);
@@ -643,7 +720,7 @@
 
   SkAutoAsciiToLC tolc(family_name);
 
-  NameToFamilyMap::const_iterator family_iterator =
+  NameToStyleSetMap::const_iterator family_iterator =
       name_to_family_map_.find(tolc.lc());
   if (family_iterator != name_to_family_map_.end()) {
     return SkRef(family_iterator->second);
@@ -652,79 +729,6 @@
   return NULL;
 }
 
-SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceNameHelper(
-    SkFontStyleSet_Cobalt* style_set,
-    SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const {
-  DCHECK(style_set != NULL);
-  if (!style) {
-    NOTREACHED() << "style should not be NULL.";
-    return NULL;
-  }
-
-  if (style->typeface == NULL) {
-    if (!style_set) {
-      return NULL;
-    }
-    style_set->CreateSystemTypeface(style);
-  }
-
-  if (style->typeface != NULL) {
-    return SkRef(style->typeface.get());
-  }
-
-  return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchFaceNameOnlyIfFound(
-    const std::string& font_face_name) const {
-  // Prioritize looking it up postscript name first since some of our client
-  // applications prefer this method to specify face names.
-  SkTypeface* typeface = matchPostScriptName(font_face_name);
-  if (typeface != NULL) return typeface;
-
-  typeface = matchFullFontFaceName(font_face_name);
-  if (typeface != NULL) return typeface;
-
-  return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceName(
-    const std::string& font_face_name) const {
-  SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
-
-  if (font_face_name.empty()) {
-    return NULL;
-  }
-
-  FullFontNameToFontFaceInfoMap::const_iterator font_face_iterator =
-      fullfontname_to_fontface_info_map_.find(font_face_name);
-
-  if (font_face_iterator != fullfontname_to_fontface_info_map_.end()) {
-    return matchFullFontFaceNameHelper(
-        font_face_iterator->second.style_set_entry_parent,
-        font_face_iterator->second.style_set_entry);
-  }
-
-  return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchPostScriptName(
-    const std::string& font_face_name) const {
-  if (font_face_name.empty()) {
-    return NULL;
-  }
-
-  PostScriptToFontFaceInfoMap::const_iterator font_face_iterator =
-      postscriptname_to_fontface_info_map_.find(font_face_name);
-  if (font_face_iterator != postscriptname_to_fontface_info_map_.end()) {
-    return matchFullFontFaceNameHelper(
-        font_face_iterator->second.style_set_entry_parent,
-        font_face_iterator->second.style_set_entry);
-  }
-
-  return NULL;
-}
-
 SkTypeface* SkFontMgr_Cobalt::onMatchFamilyStyle(
     const char family_name[], const SkFontStyle& style) const {
   SkTypeface* tf = NULL;
@@ -807,6 +811,7 @@
 
 SkTypeface* SkFontMgr_Cobalt::onCreateFromStream(SkStream* stream,
                                                  int ttc_index) const {
+  TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromStream()");
   bool is_fixed_pitch;
   SkTypeface::Style style;
   SkString name;
@@ -820,6 +825,7 @@
 
 SkTypeface* SkFontMgr_Cobalt::onCreateFromFile(const char path[],
                                                int ttc_index) const {
+  TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromFile()");
   SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
   return stream.get() ? createFromStream(stream, ttc_index) : NULL;
 }
@@ -838,6 +844,7 @@
 
 void SkFontMgr_Cobalt::BuildNameToFamilyMap(const char* base_path,
                                             SkTDArray<FontFamily*>* families) {
+  TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::BuildNameToFamilyMap()");
   for (int i = 0; i < families->count(); i++) {
     FontFamily& family = *(*families)[i];
     bool named_font = family.names.count() > 0;
@@ -861,47 +868,32 @@
              font_style_set_entry = new_set->styles_.begin();
          font_style_set_entry != new_set->styles_.end();
          ++font_style_set_entry) {
-      if (!font_style_set_entry) {
-        NOTREACHED() << " Font Style entry is invalid";
-        continue;
-      } else if ((*font_style_set_entry).get() == NULL) {
-        NOTREACHED() << " Font Style entry is NULL";
-        continue;
-      }
+      // On the first pass through, process the full font name.
+      // On the second pass through, process the font postscript name.
+      for (int i = 0; i <= 1; ++i) {
+        const std::string font_face_name_type_description =
+            i == 0 ? "Full Font" : "Postscript";
+        const std::string& font_face_name =
+            i == 0 ? (*font_style_set_entry)->full_font_name
+                   : (*font_style_set_entry)->font_postscript_name;
+        NameToStyleSetMap& font_face_name_style_set_map =
+            i == 0 ? full_font_name_to_style_set_map_
+                   : font_postscript_name_to_style_set_map_;
 
-      const std::string& full_font_name =
-          (*font_style_set_entry)->full_font_name;
-      DCHECK(!full_font_name.empty());
-      if (fullfontname_to_fontface_info_map_.find(full_font_name) ==
-          fullfontname_to_fontface_info_map_.end()) {
-        DLOG(INFO) << "Adding Full font name [" << full_font_name << "].";
-        fullfontname_to_fontface_info_map_[full_font_name] =
-            FullFontNameToFontFaceInfoMap::mapped_type(
-                font_style_set_entry->get(), new_set.get());
-      } else {
-        // Purposely, not overwriting the entry gives priority to the
-        // earlier entry.  This is consistent with how fonts.xml gives
-        // priority to fonts that are specified earlier in the file.
-        NOTREACHED() << "Full font name [" << full_font_name
-                     << "] already registered in BuildNameToFamilyMap.";
-      }
-
-      const std::string& postscript_font_name =
-          (*font_style_set_entry)->font_postscript_name;
-      DCHECK(!postscript_font_name.empty());
-      if (postscriptname_to_fontface_info_map_.find(postscript_font_name) ==
-          postscriptname_to_fontface_info_map_.end()) {
-        DLOG(INFO) << "Adding Postscript name [" << postscript_font_name
-                   << "].";
-        postscriptname_to_fontface_info_map_[postscript_font_name] =
-            PostScriptToFontFaceInfoMap::mapped_type(
-                font_style_set_entry->get(), new_set.get());
-      } else {
-        // Purposely, not overwriting the entry gives priority to the
-        // earlier entry.  This is consistent with how fonts.xml gives
-        // priority to fonts that are specified earlier in the file.
-        NOTREACHED() << "Adding Postscript name [" << postscript_font_name
-                     << "] already registered in BuildNameToFamilyMap.";
+        DCHECK(!font_face_name.empty());
+        if (font_face_name_style_set_map.find(font_face_name) ==
+            font_face_name_style_set_map.end()) {
+          DLOG(INFO) << "Adding " << font_face_name_type_description
+                     << " name [" << font_face_name << "].";
+          font_face_name_style_set_map[font_face_name] = new_set.get();
+        } else {
+          // Purposely, not overwriting the entry gives priority to the
+          // earlier entry.  This is consistent with how fonts.xml gives
+          // priority to fonts that are specified earlier in the file.
+          NOTREACHED() << font_face_name_type_description << " name ["
+                       << font_face_name
+                       << "] already registered in BuildNameToFamilyMap.";
+        }
       }
     }
 
@@ -988,6 +980,29 @@
   return NULL;
 }
 
+void SkFontMgr_Cobalt::HandlePeriodicProcessing() {
+  base::TimeTicks current_time = base::TimeTicks::Now();
+
+  ProcessSystemTypefacesWithOpenStreams(current_time);
+
+  // If the required delay has elapsed since the last font cache purge, then
+  // it's time to force another. This is accomplished by setting the limit to
+  // 1 byte smaller than it's current size, which initiates a partial purge (it
+  // always purges at least 25% of its contents). After this is done, the cache
+  // is set back to its previous size.
+  if ((current_time - last_font_cache_purge_time_).InMilliseconds() >=
+      kPeriodicFontCachePurgeDelayMs) {
+    last_font_cache_purge_time_ = current_time;
+
+    size_t font_cache_used = SkGraphics::GetFontCacheUsed();
+    if (font_cache_used > 0) {
+      size_t font_cache_limit = SkGraphics::GetFontCacheLimit();
+      SkGraphics::SetFontCacheLimit(font_cache_used - 1);
+      SkGraphics::SetFontCacheLimit(font_cache_limit);
+    }
+  }
+}
+
 // NOTE: It is the responsibility of the caller to lock
 // |system_typeface_stream_mutex_|
 void SkFontMgr_Cobalt::AddSystemTypefaceWithActiveOpenStream(
@@ -1024,26 +1039,6 @@
   }
 }
 
-void SkFontMgr_Cobalt::HandlePeriodicProcessing() {
-  base::TimeTicks current_time = base::TimeTicks::Now();
-
-  ProcessSystemTypefacesWithOpenStreams(current_time);
-
-  // If the required delay has elapsed since the last font cache purge, then
-  // it's time to force another. This is accomplished by setting the limit to
-  // 1 byte smaller than it's current size, which initiates a partial purge (it
-  // always purges at least 25% of its contents). After this is done, the cache
-  // is set back to its previous size.
-  if ((current_time - last_font_cache_purge_time_).InMilliseconds() >=
-      kPeriodicFontCachePurgeDelayMs) {
-    last_font_cache_purge_time_ = current_time;
-
-    size_t font_cache_limit = SkGraphics::GetFontCacheLimit();
-    SkGraphics::SetFontCacheLimit(SkGraphics::GetFontCacheUsed() - 1);
-    SkGraphics::SetFontCacheLimit(font_cache_limit);
-  }
-}
-
 void SkFontMgr_Cobalt::ProcessSystemTypefacesWithOpenStreams(
     const base::TimeTicks& current_time) const {
   SkAutoMutexAcquire scoped_mutex(system_typeface_stream_mutex_);
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
index cebba88..cc74881 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
@@ -46,6 +46,11 @@
 class SkFontStyleSet_Cobalt : public SkFontStyleSet {
  public:
   struct SkFontStyleSetEntry_Cobalt : public SkRefCnt {
+    // NOTE: |SkFontStyleSetEntry_Cobalt| objects are not guaranteed to last for
+    // the lifetime of |SkFontMgr_Cobalt| and can be removed by their owning
+    // |SkFontStyleSet_Cobalt| if their typeface fails to load properly. As a
+    // result, it is not safe to store their pointers outside of
+    // |SkFontStyleSet_Cobalt|.
     SkFontStyleSetEntry_Cobalt(const SkString& file_path, const int index,
                                const SkFontStyle& style,
                                const std::string& full_name,
@@ -92,6 +97,9 @@
   // calling any of the non-const private functions.
 
   SkTypeface* MatchStyleWithoutLocking(const SkFontStyle& pattern);
+  SkTypeface* MatchFullFontName(const std::string& name);
+  SkTypeface* MatchFontPostScriptName(const std::string& name);
+  SkTypeface* TryRetrieveTypefaceAndRemoveStyleOnFailure(int style_index);
   bool ContainsTypeface(const SkTypeface* typeface);
 
   bool ContainsCharacter(const SkFontStyle& style, SkUnichar character);
@@ -138,33 +146,30 @@
   SkFontMgr_Cobalt(const char* directory,
                    const SkTArray<SkString, true>& default_fonts);
 
-  // Note: Unlike the other similar onMatch* functions, this function can return
-  // NULL.  This is so that we can try other things in case the match is not
-  // found.
-  SkTypeface* matchFaceNameOnlyIfFound(const std::string& font_face_name) const;
+  // NOTE: This returns NULL if a match is not found.
+  SkTypeface* matchFaceName(const std::string& font_face_name);
 
  protected:
-  // Note: These match*Name helper functions can return NULL.
-  SkTypeface* matchFullFontFaceName(const std::string& font_face_name) const;
-  SkTypeface* matchPostScriptName(const std::string& font_face_name) const;
-  SkTypeface* matchFullFontFaceNameHelper(
-      SkFontStyleSet_Cobalt* style_set,
-      SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const;
-
   // From SkFontMgr
   virtual int onCountFamilies() const SK_OVERRIDE;
 
   virtual void onGetFamilyName(int index,
                                SkString* family_name) const SK_OVERRIDE;
 
+  // NOTE: This returns NULL if there is no accessible style set at the index.
   virtual SkFontStyleSet_Cobalt* onCreateStyleSet(int index) const SK_OVERRIDE;
 
+  // NOTE: This returns NULL if there is no family match.
   virtual SkFontStyleSet_Cobalt* onMatchFamily(const char family_name[]) const
       SK_OVERRIDE;
 
+  // NOTE: This always returns a non-NULL value. If the family name cannot be
+  // found, then the best match among the default family is returned.
   virtual SkTypeface* onMatchFamilyStyle(
       const char family_name[], const SkFontStyle& style) const SK_OVERRIDE;
 
+// NOTE: This always returns a non-NULL value. If no match can be found, then
+// the best match among the default family is returned.
 #ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
   virtual SkTypeface* onMatchFamilyStyleCharacter(
       const char family_name[], const SkFontStyle& style, const char* bcp47[],
@@ -175,19 +180,25 @@
       SkUnichar character) const SK_OVERRIDE;
 #endif
 
+  // NOTE: This returns NULL if a match is not found.
   virtual SkTypeface* onMatchFaceStyle(const SkTypeface* family_member,
                                        const SkFontStyle& font_style) const
       SK_OVERRIDE;
 
+  // NOTE: This returns NULL if the typeface cannot be created.
   virtual SkTypeface* onCreateFromData(SkData* data,
                                        int ttc_index) const SK_OVERRIDE;
 
+  // NOTE: This returns NULL if the typeface cannot be created.
   virtual SkTypeface* onCreateFromStream(SkStream* stream,
                                          int ttc_index) const SK_OVERRIDE;
 
+  // NOTE: This returns NULL if the typeface cannot be created.
   virtual SkTypeface* onCreateFromFile(const char path[],
                                        int ttc_index) const SK_OVERRIDE;
 
+  // NOTE: This always returns a non-NULL value. If no match can be found, then
+  // the best match among the default family is returned.
   virtual SkTypeface* onLegacyCreateTypeface(
       const char family_name[], unsigned style_bits) const SK_OVERRIDE;
 
@@ -201,23 +212,7 @@
     base::TimeTicks time;
   };
 
-  //  Map names to the back end so that all names for a given family refer to
-  //  the same (non-replicated) set of typefaces.
-  typedef base::hash_map<std::string, SkFontStyleSet_Cobalt*> NameToFamilyMap;
-
-  struct FontFaceInfo {
-    FontFaceInfo() : style_set_entry(NULL), style_set_entry_parent(NULL) {}
-    FontFaceInfo(SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* entry,
-                 SkFontStyleSet_Cobalt* parent)
-        : style_set_entry(entry), style_set_entry_parent(parent) {}
-
-    SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style_set_entry;
-    SkFontStyleSet_Cobalt* style_set_entry_parent;
-  };
-
-  typedef base::hash_map<std::string, FontFaceInfo>
-      FullFontNameToFontFaceInfoMap;
-  typedef base::hash_map<std::string, FontFaceInfo> PostScriptToFontFaceInfoMap;
+  typedef base::hash_map<std::string, SkFontStyleSet_Cobalt*> NameToStyleSetMap;
 
   void BuildNameToFamilyMap(const char* base_path,
                             SkTDArray<FontFamily*>* families);
@@ -257,9 +252,11 @@
   SkTArray<SkAutoTUnref<SkFontStyleSet_Cobalt>, true> font_style_sets_;
 
   SkTArray<SkString> family_names_;
-  NameToFamilyMap name_to_family_map_;
-  FullFontNameToFontFaceInfoMap fullfontname_to_fontface_info_map_;
-  PostScriptToFontFaceInfoMap postscriptname_to_fontface_info_map_;
+  //  Map names to the back end so that all names for a given family refer to
+  //  the same (non-replicated) set of typefaces.
+  NameToStyleSetMap name_to_family_map_;
+  NameToStyleSetMap full_font_name_to_style_set_map_;
+  NameToStyleSetMap font_postscript_name_to_style_set_map_;
 
   SkTArray<SkFontStyleSet_Cobalt*> fallback_families_;
 
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
index 020517c..80287a4 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
@@ -111,7 +111,7 @@
   FontStyle style;
 
   SkString full_font_name;
-  SkString postcript_name;
+  SkString postscript_name;
 };
 
 // A font family provides one or more names for a collection of fonts, each of
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
index d3af607..5a9afb7 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -127,7 +127,7 @@
   SkFontMgr_Cobalt* font_manager =
       base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get());
 
-  SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name);
+  SkTypeface* typeface = font_manager->matchFaceName(font_face_name);
   if (typeface != NULL) {
     SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface);
     return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
diff --git a/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png b/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
index d26f087..0f82d7a 100644
--- a/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
+++ b/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/renderer.gyp b/src/cobalt/renderer/renderer.gyp
index 5a1253e..d7619d5 100644
--- a/src/cobalt/renderer/renderer.gyp
+++ b/src/cobalt/renderer/renderer.gyp
@@ -22,6 +22,8 @@
       'target_name': 'renderer',
       'type': 'static_library',
       'sources': [
+        'frame_rate_throttler.cc',
+        'frame_rate_throttler.h',
         'pipeline.cc',
         'pipeline.h',
         'renderer_module.cc',
@@ -33,6 +35,9 @@
         'submission_queue.h',
       ],
 
+      'defines': [
+        'COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS=<(cobalt_minimum_frame_time_in_milliseconds)',
+      ],
       'includes': [
         'copy_font_data.gypi',
       ],
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index 7ee0e3e..c19cc0b 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -16,6 +16,7 @@
 
 #include "cobalt/renderer/renderer_module.h"
 
+#include "base/debug/trace_event.h"
 #include "cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h"
 #include "cobalt/renderer/rasterizer/blitter/software_rasterizer.h"
 #include "cobalt/renderer/rasterizer/egl/software_rasterizer.h"
@@ -30,6 +31,7 @@
 scoped_ptr<rasterizer::Rasterizer> CreateRasterizer(
     backend::GraphicsContext* graphics_context,
     const RendererModule::Options& options) {
+  TRACE_EVENT0("cobalt::renderer", "CreateRasterizer");
 #if COBALT_FORCE_STUB_RASTERIZER
   return scoped_ptr<rasterizer::Rasterizer>(new rasterizer::stub::Rasterizer());
 #else
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h b/src/cobalt/script/mozjs/mozjs_callback_function.h
index 71d8914..ef6932a 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h
@@ -27,7 +27,9 @@
 #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/util/exception_helpers.h"
 #include "cobalt/script/mozjs/weak_heap_object.h"
+#include "nb/memory_scope.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 
@@ -57,6 +59,7 @@
 
   CallbackResult<R> Run()
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -79,7 +82,8 @@
       JSBool call_result = JS::Call(context_, this_value, function, 0, NULL,
           return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -111,6 +115,7 @@
   CallbackResult<R> Run(
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -138,7 +143,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -171,6 +177,7 @@
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1,
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -199,7 +206,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -233,6 +241,7 @@
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2,
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -262,7 +271,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -297,6 +307,7 @@
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3,
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -327,7 +338,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -364,6 +376,7 @@
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4,
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -395,7 +408,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -433,6 +447,7 @@
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5,
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -465,7 +480,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -504,6 +520,7 @@
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6,
       typename base::internal::CallbackParamTraits<A7>::ForwardType a7)
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -537,7 +554,8 @@
       JSBool call_result = JS::Call(context_, this_value, function,
           kNumArguments, args, return_value.address());
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
index 861dcd3..9bfb5f2 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
@@ -32,7 +32,9 @@
 #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/util/exception_helpers.h"
 #include "cobalt/script/mozjs/weak_heap_object.h"
+#include "nb/memory_scope.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 #include "third_party/mozjs/js/src/jscntxt.h"
 
@@ -76,6 +78,7 @@
 
       typename base::internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]])
       const OVERRIDE {
+    TRACK_MEMORY_SCOPE("Javascript");
     TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
     CallbackResult<R> callback_result;
     JSAutoRequest auto_request(context_);
@@ -110,7 +113,8 @@
 ]]
 
       if (!call_result) {
-        DLOG(WARNING) << "Exception in callback.";
+        DLOG(WARNING) << "Exception in callback: "
+                      << util::GetExceptionString(context_);
         callback_result.exception = true;
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index 623a7e5..7b62f3f 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 
+#include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "cobalt/base/c_val.h"
 #include "cobalt/browser/stack_size_constants.h"
@@ -101,6 +102,7 @@
 }  // namespace
 
 MozjsEngine::MozjsEngine() : accumulated_extra_memory_cost_(0) {
+  TRACE_EVENT0("cobalt::script", "MozjsEngine::MozjsEngine()");
   // TODO: Investigate the benefit of helper threads and things like
   // parallel compilation.
   runtime_ =
@@ -147,11 +149,13 @@
 }
 
 scoped_refptr<GlobalEnvironment> MozjsEngine::CreateGlobalEnvironment() {
+  TRACE_EVENT0("cobalt::script", "MozjsEngine::CreateGlobalEnvironment()");
   DCHECK(thread_checker_.CalledOnValidThread());
   return new MozjsGlobalEnvironment(runtime_);
 }
 
 void MozjsEngine::CollectGarbage() {
+  TRACE_EVENT0("cobalt::script", "MozjsEngine::CollectGarbage()");
   DCHECK(thread_checker_.CalledOnValidThread());
   JS_GC(runtime_);
 }
@@ -196,15 +200,18 @@
     MozjsGlobalEnvironment* global_environment =
         MozjsGlobalEnvironment::GetFromContext(engine->contexts_[i]);
     if (status == JSGC_BEGIN) {
+      TRACE_EVENT_BEGIN0("cobalt::script", "SpiderMonkey Garbage Collection");
       global_environment->BeginGarbageCollection();
     } else if (status == JSGC_END) {
       global_environment->EndGarbageCollection();
+      TRACE_EVENT_END0("cobalt::script", "SpiderMonkey Garbage Collection");
     }
   }
 }
 
 void MozjsEngine::FinalizeCallback(JSFreeOp* free_op, JSFinalizeStatus status,
                                    JSBool is_compartment) {
+  TRACE_EVENT0("cobalt::script", "MozjsEngine::FinalizeCallback()");
   MozjsEngine* engine =
       static_cast<MozjsEngine*>(JS_GetRuntimePrivate(free_op->runtime()));
   DCHECK(engine->thread_checker_.CalledOnValidThread());
@@ -220,6 +227,7 @@
 }  // namespace mozjs
 
 scoped_ptr<JavaScriptEngine> JavaScriptEngine::CreateEngine() {
+  TRACE_EVENT0("cobalt::script", "JavaScriptEngine::CreateEngine()");
   return make_scoped_ptr<JavaScriptEngine>(new mozjs::MozjsEngine());
 }
 
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.cc b/src/cobalt/script/mozjs/mozjs_global_environment.cc
index 89ddeb2..b9c05a9 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.cc
@@ -28,6 +28,7 @@
 #include "cobalt/script/mozjs/proxy_handler.h"
 #include "cobalt/script/mozjs/referenced_object_map.h"
 #include "cobalt/script/mozjs/util/exception_helpers.h"
+#include "nb/memory_scope.h"
 #include "third_party/mozjs/js/src/jsfriendapi.h"
 #include "third_party/mozjs/js/src/jsfun.h"
 #include "third_party/mozjs/js/src/jsobj.h"
@@ -128,6 +129,7 @@
       environment_settings_(NULL),
       last_error_message_(NULL),
       eval_enabled_(false) {
+  TRACK_MEMORY_SCOPE("Javascript");
   context_ = JS_NewContext(runtime, kStackChunkSize);
   DCHECK(context_);
   // Set a pointer to this class inside the JSContext.
@@ -166,6 +168,7 @@
 }
 
 void MozjsGlobalEnvironment::CreateGlobalObject() {
+  TRACK_MEMORY_SCOPE("Javascript");
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!global_object_proxy_);
 
@@ -194,6 +197,7 @@
 bool MozjsGlobalEnvironment::EvaluateScript(
     const scoped_refptr<SourceCode>& source_code,
     std::string* out_result_utf8) {
+  TRACK_MEMORY_SCOPE("Javascript");
   DCHECK(thread_checker_.CalledOnValidThread());
 
   JSAutoRequest auto_request(context_);
@@ -225,6 +229,7 @@
     const scoped_refptr<SourceCode>& source_code,
     const scoped_refptr<Wrappable>& owning_object,
     base::optional<OpaqueHandleHolder::Reference>* out_opaque_handle) {
+  TRACK_MEMORY_SCOPE("Javascript");
   DCHECK(thread_checker_.CalledOnValidThread());
   JSAutoRequest auto_request(context_);
   JSAutoCompartment auto_compartment(context_, global_object_proxy_);
@@ -245,6 +250,7 @@
 bool MozjsGlobalEnvironment::EvaluateScriptInternal(
     const scoped_refptr<SourceCode>& source_code,
     JS::MutableHandleValue out_result) {
+  TRACK_MEMORY_SCOPE("Javascript");
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(global_object_proxy_);
   MozjsSourceCode* mozjs_source_code =
@@ -291,6 +297,7 @@
 
 void MozjsGlobalEnvironment::AllowGarbageCollection(
     const scoped_refptr<Wrappable>& wrappable) {
+  TRACK_MEMORY_SCOPE("Javascript");
   DCHECK(thread_checker_.CalledOnValidThread());
   CachedWrapperMultiMap::iterator it =
       kept_alive_objects_.find(wrappable.get());
@@ -320,6 +327,7 @@
 
 void MozjsGlobalEnvironment::Bind(const std::string& identifier,
                                   const scoped_refptr<Wrappable>& impl) {
+  TRACK_MEMORY_SCOPE("Javascript");
   JSAutoRequest auto_request(context_);
   JSAutoCompartment auto_compartment(context_, global_object_proxy_);
 
@@ -342,12 +350,14 @@
 }
 
 void MozjsGlobalEnvironment::DoSweep() {
+  TRACK_MEMORY_SCOPE("Javascript");
   weak_object_manager_.SweepUnmarkedObjects();
   // Remove NULL references after sweeping weak references.
   referenced_objects_->RemoveNullReferences();
 }
 
 void MozjsGlobalEnvironment::BeginGarbageCollection() {
+  TRACK_MEMORY_SCOPE("Javascript");
   // It's possible that a GC could be triggered from within the
   // BeginGarbageCollection callback. Only create the OpaqueRootState the first
   // time we enter.
@@ -461,6 +471,7 @@
 }
 
 JSBool MozjsGlobalEnvironment::CheckEval(JSContext* context) {
+  TRACK_MEMORY_SCOPE("Javascript");
   MozjsGlobalEnvironment* global_object_proxy = GetFromContext(context);
   DCHECK(global_object_proxy);
   if (!global_object_proxy->report_eval_.is_null()) {
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.cc b/src/cobalt/script/mozjs/util/exception_helpers.cc
index ce0ca06..3a4b80c 100644
--- a/src/cobalt/script/mozjs/util/exception_helpers.cc
+++ b/src/cobalt/script/mozjs/util/exception_helpers.cc
@@ -28,6 +28,25 @@
 namespace script {
 namespace mozjs {
 namespace util {
+std::string GetExceptionString(JSContext* context) {
+  if (!JS_IsExceptionPending(context)) {
+    return std::string("No exception pending.");
+  }
+  JS::RootedValue exception(context);
+  JS_GetPendingException(context, exception.address());
+  JS_ReportPendingException(context);
+  return GetExceptionString(context, exception);
+}
+
+std::string GetExceptionString(JSContext* context,
+                               JS::HandleValue exception) {
+  std::string exception_string;
+  MozjsExceptionState exception_state(context);
+  FromJSValue(context, exception, kNoConversionFlags, &exception_state,
+              &exception_string);
+  return exception_string;
+}
+
 std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames) {
   JSAutoRequest auto_request(context);
   JS::StackDescription* stack_description =
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.h b/src/cobalt/script/mozjs/util/exception_helpers.h
index 75dff27..7e5e563 100644
--- a/src/cobalt/script/mozjs/util/exception_helpers.h
+++ b/src/cobalt/script/mozjs/util/exception_helpers.h
@@ -16,6 +16,7 @@
 #ifndef COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
 #define COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
 
+#include <string>
 #include <vector>
 
 #include "cobalt/script/stack_frame.h"
@@ -25,6 +26,10 @@
 namespace script {
 namespace mozjs {
 namespace util {
+std::string GetExceptionString(JSContext* context);
+
+std::string GetExceptionString(JSContext* context, JS::HandleValue exception);
+
 std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames);
 }  // namespace util
 }  // namespace mozjs
diff --git a/src/cobalt/script/script.gyp b/src/cobalt/script/script.gyp
index c827de2..46cc245 100644
--- a/src/cobalt/script/script.gyp
+++ b/src/cobalt/script/script.gyp
@@ -38,6 +38,7 @@
       ],
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
+        '<(DEPTH)/nb/nb.gyp:nb',
       ]
     },
     {
diff --git a/src/cobalt/speech/microphone_manager.cc b/src/cobalt/speech/microphone_manager.cc
index ea3ba7d..4414a77 100644
--- a/src/cobalt/speech/microphone_manager.cc
+++ b/src/cobalt/speech/microphone_manager.cc
@@ -16,12 +16,6 @@
 
 #include "cobalt/speech/microphone_manager.h"
 
-#if defined(ENABLE_FAKE_MICROPHONE)
-#include "cobalt/speech/microphone_fake.h"
-#endif  // defined(ENABLE_FAKE_MICROPHONE)
-#if defined(SB_USE_SB_MICROPHONE)
-#include "cobalt/speech/microphone_starboard.h"
-#endif  // defined(SB_USE_SB_MICROPHONE)
 #include "cobalt/speech/speech_recognition_error.h"
 
 namespace cobalt {
@@ -34,26 +28,16 @@
 const float kMicReadRateInHertz = 60.0f;
 }  // namespace
 
-MicrophoneManager::MicrophoneManager(int sample_rate,
-                                     const DataReceivedCallback& data_received,
-                                     const CompletionCallback& completion,
-                                     const ErrorCallback& error,
-                                     const Microphone::Options& options)
-    : sample_rate_(sample_rate),
-      data_received_callback_(data_received),
+MicrophoneManager::MicrophoneManager(
+    const DataReceivedCallback& data_received,
+    const CompletionCallback& completion, const ErrorCallback& error,
+    const MicrophoneCreator& microphone_creator)
+    : data_received_callback_(data_received),
       completion_callback_(completion),
       error_callback_(error),
-#if defined(ENABLE_FAKE_MICROPHONE)
-      microphone_options_(options),
-#endif  // defined(ENABLE_FAKE_MICROPHONE)
+      microphone_creator_(microphone_creator),
       state_(kStopped),
       thread_("microphone_thread") {
-  UNREFERENCED_PARAMETER(sample_rate_);
-#if defined(ENABLE_FAKE_MICROPHONE)
-  UNREFERENCED_PARAMETER(microphone_options_);
-#else
-  UNREFERENCED_PARAMETER(options);
-#endif  // defined(ENABLE_FAKE_MICROPHONE)
   thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
 }
 
@@ -82,19 +66,7 @@
     return true;
   }
 
-#if defined(SB_USE_SB_MICROPHONE)
-#if defined(ENABLE_FAKE_MICROPHONE)
-  if (microphone_options_.enable_fake_microphone) {
-    microphone_.reset(new MicrophoneFake(microphone_options_));
-  } else {
-    microphone_.reset(
-        new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
-  }
-#else
-  microphone_.reset(new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
-#endif  // defined(ENABLE_FAKE_MICROPHONE)
-#endif  // defined(SB_USE_SB_MICROPHONE)
-
+  microphone_ = microphone_creator_.Run(kBufferSizeInBytes);
   if (microphone_ && microphone_->IsValid()) {
     state_ = kStopped;
     return true;
@@ -163,7 +135,7 @@
   DCHECK(microphone_);
   DCHECK(microphone_->MinMicrophoneReadInBytes() <= kBufferSizeInBytes);
 
-  static int16_t samples[kBufferSizeInBytes / sizeof(int16_t)];
+  int16_t samples[kBufferSizeInBytes / sizeof(int16_t)];
   int read_bytes =
       microphone_->Read(reinterpret_cast<char*>(samples), kBufferSizeInBytes);
   // If |read_bytes| is zero, nothing should happen.
diff --git a/src/cobalt/speech/microphone_manager.h b/src/cobalt/speech/microphone_manager.h
index c07c21a..08eaf6e 100644
--- a/src/cobalt/speech/microphone_manager.h
+++ b/src/cobalt/speech/microphone_manager.h
@@ -38,11 +38,12 @@
   typedef base::Callback<void(scoped_ptr<ShellAudioBus>)> DataReceivedCallback;
   typedef base::Callback<void(void)> CompletionCallback;
   typedef base::Callback<void(const scoped_refptr<dom::Event>&)> ErrorCallback;
+  typedef base::Callback<scoped_ptr<Microphone>(int)> MicrophoneCreator;
 
-  MicrophoneManager(int sample_rate, const DataReceivedCallback& data_received,
+  MicrophoneManager(const DataReceivedCallback& data_received,
                     const CompletionCallback& completion,
                     const ErrorCallback& error,
-                    const Microphone::Options& options);
+                    const MicrophoneCreator& microphone_creator);
 
   ~MicrophoneManager();
 
@@ -65,15 +66,12 @@
   // Timer callback for fetching audio data.
   void Read();
 
-  int sample_rate_;
   const DataReceivedCallback data_received_callback_;
   const CompletionCallback completion_callback_;
   const ErrorCallback error_callback_;
+  const MicrophoneCreator microphone_creator_;
 
   scoped_ptr<Microphone> microphone_;
-#if defined(ENABLE_FAKE_MICROPHONE)
-  Microphone::Options microphone_options_;
-#endif  // defined(ENABLE_FAKE_MICROPHONE)
 
   // Microphone state.
   State state_;
diff --git a/src/cobalt/speech/speech.gyp b/src/cobalt/speech/speech.gyp
index 4d431dd..c016372 100644
--- a/src/cobalt/speech/speech.gyp
+++ b/src/cobalt/speech/speech.gyp
@@ -77,6 +77,8 @@
           'sources': [
             'microphone_fake.cc',
             'microphone_fake.h',
+            'url_fetcher_fake.cc',
+            'url_fetcher_fake.h',
           ],
           'defines': [
             'ENABLE_FAKE_MICROPHONE',
diff --git a/src/cobalt/speech/speech_recognition_manager.cc b/src/cobalt/speech/speech_recognition_manager.cc
index 0b4ffdf..4eab7de 100644
--- a/src/cobalt/speech/speech_recognition_manager.cc
+++ b/src/cobalt/speech/speech_recognition_manager.cc
@@ -19,7 +19,15 @@
 #include "base/bind.h"
 #include "cobalt/base/tokens.h"
 #include "cobalt/dom/dom_exception.h"
+#if defined(ENABLE_FAKE_MICROPHONE)
+#include "cobalt/speech/microphone_fake.h"
+#include "cobalt/speech/url_fetcher_fake.h"
+#endif  // defined(ENABLE_FAKE_MICROPHONE)
 #include "cobalt/speech/microphone_manager.h"
+#if defined(SB_USE_SB_MICROPHONE)
+#include "cobalt/speech/microphone_starboard.h"
+#endif  // defined(SB_USE_SB_MICROPHONE)
+#include "net/url_request/url_fetcher.h"
 
 namespace cobalt {
 namespace speech {
@@ -27,6 +35,40 @@
 namespace {
 const int kSampleRate = 16000;
 const float kAudioPacketDurationInSeconds = 0.1f;
+
+scoped_ptr<net::URLFetcher> CreateURLFetcher(
+    const GURL& url, net::URLFetcher::RequestType request_type,
+    net::URLFetcherDelegate* delegate) {
+  return make_scoped_ptr<net::URLFetcher>(
+      net::URLFetcher::Create(url, request_type, delegate));
+}
+
+scoped_ptr<Microphone> CreateMicrophone(int buffer_size_bytes) {
+#if defined(SB_USE_SB_MICROPHONE)
+  return make_scoped_ptr<Microphone>(
+      new MicrophoneStarboard(kSampleRate, buffer_size_bytes));
+#else
+  UNREFERENCED_PARAMETER(buffer_size_bytes);
+  return scoped_ptr<Microphone>();
+#endif  // defined(SB_USE_SB_MICROPHONE)
+}
+
+#if defined(SB_USE_SB_MICROPHONE)
+#if defined(ENABLE_FAKE_MICROPHONE)
+scoped_ptr<net::URLFetcher> CreateFakeURLFetcher(
+    const GURL& url, net::URLFetcher::RequestType request_type,
+    net::URLFetcherDelegate* delegate) {
+  return make_scoped_ptr<net::URLFetcher>(
+      new URLFetcherFake(url, request_type, delegate));
+}
+
+scoped_ptr<Microphone> CreateFakeMicrophone(const Microphone::Options& options,
+                                            int /*buffer_size_bytes*/) {
+  return make_scoped_ptr<Microphone>(new MicrophoneFake(options));
+}
+#endif  // defined(ENABLE_FAKE_MICROPHONE)
+#endif  // defined(SB_USE_SB_MICROPHONE)
+
 }  // namespace
 
 SpeechRecognitionManager::SpeechRecognitionManager(
@@ -36,20 +78,38 @@
       weak_this_(weak_ptr_factory_.GetWeakPtr()),
       main_message_loop_(base::MessageLoopProxy::current()),
       event_callback_(event_callback),
-      ALLOW_THIS_IN_INITIALIZER_LIST(
-          recognizer_(network_module,
-                      base::Bind(&SpeechRecognitionManager::OnRecognizerEvent,
-                                 base::Unretained(this)))),
-      ALLOW_THIS_IN_INITIALIZER_LIST(microphone_manager_(new MicrophoneManager(
-          kSampleRate, base::Bind(&SpeechRecognitionManager::OnDataReceived,
-                                  base::Unretained(this)),
-          base::Bind(&SpeechRecognitionManager::OnDataCompletion,
-                     base::Unretained(this)),
-          base::Bind(&SpeechRecognitionManager::OnMicError,
-                     base::Unretained(this)),
-          microphone_options))),
       endpointer_delegate_(kSampleRate),
-      state_(kStopped) {}
+      state_(kStopped) {
+  UNREFERENCED_PARAMETER(microphone_options);
+
+  SpeechRecognizer::URLFetcherCreator url_fetcher_creator =
+      base::Bind(&CreateURLFetcher);
+  MicrophoneManager::MicrophoneCreator microphone_creator =
+      base::Bind(&CreateMicrophone);
+
+#if defined(SB_USE_SB_MICROPHONE)
+#if defined(ENABLE_FAKE_MICROPHONE)
+  if (microphone_options.enable_fake_microphone) {
+    // If fake microphone is enabled, fake URL fetchers should be enabled as
+    // well.
+    url_fetcher_creator = base::Bind(&CreateFakeURLFetcher);
+    microphone_creator = base::Bind(&CreateFakeMicrophone, microphone_options);
+  }
+#endif  // defined(ENABLE_FAKE_MICROPHONE)
+#endif  // defined(SB_USE_SB_MICROPHONE)
+
+  recognizer_.reset(new SpeechRecognizer(
+      network_module, base::Bind(&SpeechRecognitionManager::OnRecognizerEvent,
+                                 base::Unretained(this)),
+      url_fetcher_creator));
+  microphone_manager_.reset(new MicrophoneManager(
+      base::Bind(&SpeechRecognitionManager::OnDataReceived,
+                 base::Unretained(this)),
+      base::Bind(&SpeechRecognitionManager::OnDataCompletion,
+                 base::Unretained(this)),
+      base::Bind(&SpeechRecognitionManager::OnMicError, base::Unretained(this)),
+      microphone_creator));
+}
 
 SpeechRecognitionManager::~SpeechRecognitionManager() { Stop(); }
 
@@ -65,7 +125,7 @@
     return;
   }
 
-  recognizer_.Start(config, kSampleRate);
+  recognizer_->Start(config, kSampleRate);
   microphone_manager_->Open();
   endpointer_delegate_.Start();
   state_ = kStarted;
@@ -82,7 +142,7 @@
 
   endpointer_delegate_.Stop();
   microphone_manager_->Close();
-  recognizer_.Stop();
+  recognizer_->Stop();
   state_ = kStopped;
   event_callback_.Run(new dom::Event(base::Tokens::soundend()));
 }
@@ -98,7 +158,7 @@
 
   endpointer_delegate_.Stop();
   microphone_manager_->Close();
-  recognizer_.Stop();
+  recognizer_->Stop();
   state_ = kAborted;
   event_callback_.Run(new dom::Event(base::Tokens::soundend()));
 }
@@ -118,7 +178,7 @@
     if (endpointer_delegate_.IsFirstTimeSoundStarted(*audio_bus)) {
       event_callback_.Run(new dom::Event(base::Tokens::soundstart()));
     }
-    recognizer_.RecognizeAudio(audio_bus.Pass(), false);
+    recognizer_->RecognizeAudio(audio_bus.Pass(), false);
   }
 }
 
@@ -140,7 +200,7 @@
     scoped_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus(
         1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved));
     dummy_audio_bus->ZeroAllFrames();
-    recognizer_.RecognizeAudio(dummy_audio_bus.Pass(), true);
+    recognizer_->RecognizeAudio(dummy_audio_bus.Pass(), true);
   }
 }
 
@@ -174,7 +234,7 @@
 
   // An error is occured in Mic, so stop the energy endpointer and recognizer.
   endpointer_delegate_.Stop();
-  recognizer_.Stop();
+  recognizer_->Stop();
   state_ = kAborted;
   event_callback_.Run(new dom::Event(base::Tokens::soundend()));
 }
diff --git a/src/cobalt/speech/speech_recognition_manager.h b/src/cobalt/speech/speech_recognition_manager.h
index 6f0faa7..2d622dd 100644
--- a/src/cobalt/speech/speech_recognition_manager.h
+++ b/src/cobalt/speech/speech_recognition_manager.h
@@ -80,7 +80,7 @@
 
   // Callback for sending dom events if available.
   EventCallback event_callback_;
-  SpeechRecognizer recognizer_;
+  scoped_ptr<SpeechRecognizer> recognizer_;
 
   scoped_ptr<MicrophoneManager> microphone_manager_;
 
diff --git a/src/cobalt/speech/speech_recognizer.cc b/src/cobalt/speech/speech_recognizer.cc
index 902fd48..17806b8 100644
--- a/src/cobalt/speech/speech_recognizer.cc
+++ b/src/cobalt/speech/speech_recognizer.cc
@@ -164,10 +164,12 @@
 }  // namespace
 
 SpeechRecognizer::SpeechRecognizer(network::NetworkModule* network_module,
-                                   const EventCallback& event_callback)
+                                   const EventCallback& event_callback,
+                                   const URLFetcherCreator& fetcher_creator)
     : network_module_(network_module),
       started_(false),
       event_callback_(event_callback),
+      fetcher_creator_(fetcher_creator),
       thread_("speech_recognizer") {
   thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
 }
@@ -264,8 +266,8 @@
   // Use protobuffer as the output format.
   down_url = AppendQueryParameter(down_url, "output", "pb");
 
-  downstream_fetcher_.reset(
-      net::URLFetcher::Create(down_url, net::URLFetcher::GET, this));
+  downstream_fetcher_ =
+      fetcher_creator_.Run(down_url, net::URLFetcher::GET, this);
   downstream_fetcher_->SetRequestContext(
       network_module_->url_request_context_getter());
   downstream_fetcher_->Start();
@@ -312,8 +314,7 @@
     up_url = AppendQueryParameter(up_url, "interim", "");
   }
 
-  upstream_fetcher_.reset(
-      net::URLFetcher::Create(up_url, net::URLFetcher::POST, this));
+  upstream_fetcher_ = fetcher_creator_.Run(up_url, net::URLFetcher::POST, this);
   upstream_fetcher_->SetRequestContext(
       network_module_->url_request_context_getter());
   upstream_fetcher_->SetChunkedUpload(encoder_->GetMimeType());
diff --git a/src/cobalt/speech/speech_recognizer.h b/src/cobalt/speech/speech_recognizer.h
index 55cd68f..5dac2c6 100644
--- a/src/cobalt/speech/speech_recognizer.h
+++ b/src/cobalt/speech/speech_recognizer.h
@@ -46,9 +46,13 @@
   typedef base::Callback<void(const scoped_refptr<dom::Event>&)> EventCallback;
   typedef SpeechRecognitionResultList::SpeechRecognitionResults
       SpeechRecognitionResults;
+  typedef base::Callback<scoped_ptr<net::URLFetcher>(
+      const GURL&, net::URLFetcher::RequestType, net::URLFetcherDelegate*)>
+      URLFetcherCreator;
 
   SpeechRecognizer(network::NetworkModule* network_module,
-                   const EventCallback& event_callback);
+                   const EventCallback& event_callback,
+                   const URLFetcherCreator& fetcher_creator);
   ~SpeechRecognizer() OVERRIDE;
 
   // Multiple calls to Start/Stop are allowed, the implementation should take
@@ -86,7 +90,10 @@
   scoped_ptr<net::URLFetcher> upstream_fetcher_;
   // Fetcher for receiving the streaming results.
   scoped_ptr<net::URLFetcher> downstream_fetcher_;
-  EventCallback event_callback_;
+  // Used to send speech recognition event.
+  const EventCallback event_callback_;
+  // Used to create url fetcher.
+  const URLFetcherCreator fetcher_creator_;
   // Used for processing proto buffer data.
   content::ChunkedByteBuffer chunked_byte_buffer_;
   // Used for accumulating final results.
diff --git a/src/cobalt/speech/url_fetcher_fake.cc b/src/cobalt/speech/url_fetcher_fake.cc
new file mode 100644
index 0000000..2d621cb
--- /dev/null
+++ b/src/cobalt/speech/url_fetcher_fake.cc
@@ -0,0 +1,176 @@
+/*
+ * 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/speech/url_fetcher_fake.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include "base/basictypes.h"
+#include "base/sys_byteorder.h"
+#include "cobalt/speech/google_streaming_api.pb.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+namespace cobalt {
+namespace speech {
+namespace {
+const int kDownloadTimerInterval = 100;
+
+struct RecognitionAlternative {
+  const char* transcript;
+  float confidence;
+};
+
+const RecognitionAlternative kAlternatives_1[] = {
+    {"tube", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_2[] = {
+    {"to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_3[] = {
+    {" or not", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_4[] = {
+    {" or not to be", 0.0f}, {"to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_5[] = {
+    {"to be or not to be", 0.728f}, {"2 B or not to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_6[] = {
+    {"that", 0.0f}, {"is the", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_7[] = {
+    {"that", 0.0f}, {"is the question", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_8[] = {
+    {"that is", 0.0f}, {"the question", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_9[] = {
+    {"that is the question", 0.8577f}, {"that is a question", 0.0f},
+};
+
+struct RecognitionResult {
+  const RecognitionAlternative* alternatives;
+  bool final;
+  size_t number_of_alternatives;
+};
+
+const RecognitionResult kRecognitionResults[] = {
+    {kAlternatives_1, false, SB_ARRAY_SIZE_INT(kAlternatives_1)},
+    {kAlternatives_2, false, SB_ARRAY_SIZE_INT(kAlternatives_2)},
+    {kAlternatives_3, false, SB_ARRAY_SIZE_INT(kAlternatives_3)},
+    {kAlternatives_4, false, SB_ARRAY_SIZE_INT(kAlternatives_4)},
+    {kAlternatives_5, true, SB_ARRAY_SIZE_INT(kAlternatives_5)},
+    {kAlternatives_6, false, SB_ARRAY_SIZE_INT(kAlternatives_6)},
+    {kAlternatives_7, false, SB_ARRAY_SIZE_INT(kAlternatives_7)},
+    {kAlternatives_8, false, SB_ARRAY_SIZE_INT(kAlternatives_8)},
+    {kAlternatives_9, true, SB_ARRAY_SIZE_INT(kAlternatives_9)},
+};
+
+std::string GetMockProtoResult(int index) {
+  proto::SpeechRecognitionEvent proto_event;
+  proto_event.set_status(proto::SpeechRecognitionEvent::STATUS_SUCCESS);
+  proto::SpeechRecognitionResult* proto_result = proto_event.add_result();
+  proto_result->set_final(kRecognitionResults[index].final);
+  const RecognitionAlternative* recognition_alternatives =
+      kRecognitionResults[index].alternatives;
+
+  for (size_t i = 0; i < kRecognitionResults[index].number_of_alternatives;
+       ++i) {
+    proto::SpeechRecognitionAlternative* proto_alternative =
+        proto_result->add_alternative();
+    proto_alternative->set_confidence(recognition_alternatives[i].confidence);
+    proto_alternative->set_transcript(recognition_alternatives[i].transcript);
+  }
+
+  std::string response_string;
+  proto_event.SerializeToString(&response_string);
+
+  // Prepend 4 byte prefix length indication to the protobuf message as
+  // envisaged by the google streaming recognition webservice protocol.
+  uint32_t prefix =
+      base::HostToNet32(static_cast<uint32_t>(response_string.size()));
+  response_string.insert(0, reinterpret_cast<char*>(&prefix), sizeof(prefix));
+  return response_string;
+}
+
+}  // namespace
+
+URLFetcherFake::URLFetcherFake(const GURL& url,
+                               net::URLFetcher::RequestType /*request_type*/,
+                               net::URLFetcherDelegate* delegate)
+    : original_url_(url),
+      delegate_(delegate),
+      is_chunked_upload_(false),
+      download_index_(0) {}
+
+URLFetcherFake::~URLFetcherFake() {}
+
+void URLFetcherFake::SetChunkedUpload(
+    const std::string& /*upload_content_type*/) {
+  is_chunked_upload_ = true;
+}
+
+void URLFetcherFake::AppendChunkToUpload(const std::string& /*data*/,
+                                         bool /*is_last_chunk*/) {
+  SB_DCHECK(is_chunked_upload_);
+  // no-op.
+}
+
+void URLFetcherFake::SetRequestContext(
+    net::URLRequestContextGetter* /*request_context_getter*/) {
+  // no-op.
+}
+
+void URLFetcherFake::Start() {
+  if (!is_chunked_upload_) {
+    download_timer_.emplace();
+    download_timer_->Start(
+        FROM_HERE, base::TimeDelta::FromMilliseconds(kDownloadTimerInterval),
+        this, &URLFetcherFake::OnURLFetchDownloadData);
+  }
+}
+
+const net::URLRequestStatus& URLFetcherFake::GetStatus() const {
+  return fake_status_;
+}
+
+int URLFetcherFake::GetResponseCode() const { return 200; }
+
+void URLFetcherFake::OnURLFetchDownloadData() {
+  SB_DCHECK(!is_chunked_upload_);
+  std::string result = GetMockProtoResult(download_index_);
+  delegate_->OnURLFetchDownloadData(
+      this, make_scoped_ptr<std::string>(new std::string(result)));
+  download_index_++;
+  if (download_index_ ==
+      static_cast<int>(SB_ARRAY_SIZE_INT(kRecognitionResults))) {
+    download_index_ = 0;
+    download_timer_->Stop();
+  }
+}
+
+}  // namespace speech
+}  // namespace cobalt
+
+#endif  // defined(ENABLE_FAKE_MICROPHONE)
diff --git a/src/cobalt/speech/url_fetcher_fake.h b/src/cobalt/speech/url_fetcher_fake.h
new file mode 100644
index 0000000..cf3c150
--- /dev/null
+++ b/src/cobalt/speech/url_fetcher_fake.h
@@ -0,0 +1,156 @@
+/*
+ * 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_SPEECH_URL_FETCHER_FAKE_H_
+#define COBALT_SPEECH_URL_FETCHER_FAKE_H_
+
+#include "cobalt/speech/speech_configuration.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include <string>
+
+#include "base/optional.h"
+#include "base/timer.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/host_port_pair.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+
+namespace cobalt {
+namespace speech {
+
+class URLFetcherFake : public net::URLFetcher {
+ public:
+  URLFetcherFake(const GURL& url, net::URLFetcher::RequestType request_type,
+                 net::URLFetcherDelegate* delegate);
+  virtual ~URLFetcherFake();
+
+  // URLFetcher implementation:
+  void SetUploadData(const std::string& /*upload_content_type*/,
+                     const std::string& /*upload_content*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void SetChunkedUpload(const std::string& /*upload_content_type*/) OVERRIDE;
+  void AppendChunkToUpload(const std::string& data,
+                           bool is_last_chunk) OVERRIDE;
+  void SetLoadFlags(int /*load_flags*/) OVERRIDE { NOTREACHED(); }
+  int GetLoadFlags() const OVERRIDE {
+    NOTREACHED();
+    return 0;
+  }
+  void SetReferrer(const std::string& /*referrer*/) OVERRIDE { NOTREACHED(); }
+  void SetExtraRequestHeaders(
+      const std::string& /*extra_request_headers*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void AddExtraRequestHeader(const std::string& /*header_line*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void GetExtraRequestHeaders(
+      net::HttpRequestHeaders* /*headers*/) const OVERRIDE {
+    NOTREACHED();
+  }
+  void SetRequestContext(
+      net::URLRequestContextGetter* request_context_getter) OVERRIDE;
+  void SetFirstPartyForCookies(
+      const GURL& /*first_party_for_cookies*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void SetURLRequestUserData(
+      const void* /*key*/,
+      const CreateDataCallback& /*create_data_callback*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void SetStopOnRedirect(bool /*stop_on_redirect*/) OVERRIDE { NOTREACHED(); }
+  void SetAutomaticallyRetryOn5xx(bool /*retry*/) OVERRIDE { NOTREACHED(); }
+  void SetMaxRetriesOn5xx(int /*max_retries*/) OVERRIDE { NOTREACHED(); }
+  int GetMaxRetriesOn5xx() const OVERRIDE {
+    NOTREACHED();
+    return 0;
+  }
+  base::TimeDelta GetBackoffDelay() const OVERRIDE {
+    NOTREACHED();
+    return base::TimeDelta();
+  }
+  void SetAutomaticallyRetryOnNetworkChanges(int /*max_retries*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void SaveResponseToFileAtPath(
+      const FilePath& /*file_path*/,
+      scoped_refptr<base::TaskRunner> /*file_task_runner*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void SaveResponseToTemporaryFile(
+      scoped_refptr<base::TaskRunner> /*file_task_runner*/) OVERRIDE {
+    NOTREACHED();
+  }
+  void DiscardResponse() OVERRIDE { NOTREACHED(); }
+  net::HttpResponseHeaders* GetResponseHeaders() const OVERRIDE {
+    NOTREACHED();
+    return NULL;
+  }
+  net::HostPortPair GetSocketAddress() const OVERRIDE {
+    NOTREACHED();
+    return net::HostPortPair();
+  }
+  bool WasFetchedViaProxy() const OVERRIDE {
+    NOTREACHED();
+    return false;
+  }
+  void Start() OVERRIDE;
+  const GURL& GetOriginalURL() const OVERRIDE { return original_url_; }
+  const GURL& GetURL() const OVERRIDE { return original_url_; }
+  const net::URLRequestStatus& GetStatus() const OVERRIDE;
+  int GetResponseCode() const OVERRIDE;
+  const net::ResponseCookies& GetCookies() const OVERRIDE {
+    NOTREACHED();
+    return fake_cookies_;
+  }
+  bool FileErrorOccurred(
+      base::PlatformFileError* /*out_error_code*/) const OVERRIDE {
+    NOTREACHED();
+    return false;
+  }
+  void ReceivedContentWasMalformed() OVERRIDE { NOTREACHED(); }
+  bool GetResponseAsString(
+      std::string* /*out_response_string*/) const OVERRIDE {
+    NOTREACHED();
+    return false;
+  }
+  bool GetResponseAsFilePath(bool /*take_ownership*/,
+                             FilePath* /*out_response_path*/) const OVERRIDE {
+    NOTREACHED();
+    return false;
+  }
+
+ private:
+  void OnURLFetchDownloadData();
+
+  GURL original_url_;
+  net::URLFetcherDelegate* delegate_;
+  bool is_chunked_upload_;
+  int download_index_;
+  net::ResponseCookies fake_cookies_;
+  net::URLRequestStatus fake_status_;
+  base::optional<base::RepeatingTimer<URLFetcherFake> > download_timer_;
+};
+
+}  // namespace speech
+}  // namespace cobalt
+
+#endif  // defined(ENABLE_FAKE_MICROPHONE)
+#endif  // COBALT_SPEECH_URL_FETCHER_FAKE_H_
diff --git a/src/cobalt/storage/virtual_file.cc b/src/cobalt/storage/virtual_file.cc
index 64904c2..dcb93ed 100644
--- a/src/cobalt/storage/virtual_file.cc
+++ b/src/cobalt/storage/virtual_file.cc
@@ -87,7 +87,10 @@
     buffer_.resize(offset + bytes);
   }
 
-  memcpy(&buffer_[offset], source, bytes);
+  if (!buffer_.empty()) {
+    // std::vector does not define access to underlying array when empty
+    memcpy(&buffer_[offset], source, bytes);
+  }
   return bytes_in;
 }
 
diff --git a/src/cobalt/system_window/starboard/system_window.cc b/src/cobalt/system_window/starboard/system_window.cc
index 331e028..2f1b24a 100644
--- a/src/cobalt/system_window/starboard/system_window.cc
+++ b/src/cobalt/system_window/starboard/system_window.cc
@@ -103,6 +103,15 @@
   return math::Size(window_size.width, window_size.height);
 }
 
+float SystemWindowStarboard::GetVideoPixelRatio() const {
+  SbWindowSize window_size;
+  if (!SbWindowGetSize(window_, &window_size)) {
+    DLOG(WARNING) << "SbWindowGetSize() failed.";
+    return 1.0;
+  }
+  return window_size.video_pixel_ratio;
+}
+
 SbWindow SystemWindowStarboard::GetSbWindow() { return window_; }
 
 void* SystemWindowStarboard::GetWindowHandle() {
diff --git a/src/cobalt/system_window/starboard/system_window.h b/src/cobalt/system_window/starboard/system_window.h
index 7d6a76e..b733bb9 100644
--- a/src/cobalt/system_window/starboard/system_window.h
+++ b/src/cobalt/system_window/starboard/system_window.h
@@ -36,6 +36,7 @@
   ~SystemWindowStarboard() OVERRIDE;
 
   math::Size GetWindowSize() const OVERRIDE;
+  float GetVideoPixelRatio() const OVERRIDE;
 
   // Returns a handle to the Starboard window object.
   SbWindow GetSbWindow();
diff --git a/src/cobalt/system_window/system_window.h b/src/cobalt/system_window/system_window.h
index 4695652..82683e0 100644
--- a/src/cobalt/system_window/system_window.h
+++ b/src/cobalt/system_window/system_window.h
@@ -74,6 +74,11 @@
   // Returns the dimensions of the window.
   virtual math::Size GetWindowSize() const = 0;
 
+  // video pixel ratio = resolution of video output / resolution of window.  Its
+  // value is usually 1.0.  Set it to a value greater than 1.0 allows the video
+  // to be played in higher resolution than the window.
+  virtual float GetVideoPixelRatio() const { return 1.f; }
+
   base::EventDispatcher* event_dispatcher() const { return event_dispatcher_; }
 
  private:
diff --git a/src/cobalt/webdriver/element_driver.cc b/src/cobalt/webdriver/element_driver.cc
index 950581a..d295974 100644
--- a/src/cobalt/webdriver/element_driver.cc
+++ b/src/cobalt/webdriver/element_driver.cc
@@ -105,7 +105,7 @@
   Keyboard::TranslateToKeyEvents(keys.utf8_keys(), Keyboard::kReleaseModifiers,
                                  events.get());
   // Dispatch the keyboard events.
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       element_message_loop_,
       base::Bind(&ElementDriver::SendKeysInternal, base::Unretained(this),
                  base::Passed(&events)),
@@ -114,7 +114,7 @@
 
 util::CommandResult<protocol::ElementId> ElementDriver::FindElement(
     const protocol::SearchStrategy& strategy) {
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       element_message_loop_,
       base::Bind(&ElementDriver::FindElementsInternal<protocol::ElementId>,
                  base::Unretained(this), strategy),
@@ -123,7 +123,7 @@
 
 util::CommandResult<std::vector<protocol::ElementId> >
 ElementDriver::FindElements(const protocol::SearchStrategy& strategy) {
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       element_message_loop_,
       base::Bind(&ElementDriver::FindElementsInternal<ElementIdVector>,
                  base::Unretained(this), strategy),
@@ -132,7 +132,7 @@
 
 util::CommandResult<bool> ElementDriver::Equals(
     const ElementDriver* other_element_driver) {
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       element_message_loop_,
       base::Bind(&ElementDriver::EqualsInternal, base::Unretained(this),
                  other_element_driver),
diff --git a/src/cobalt/webdriver/session_driver.cc b/src/cobalt/webdriver/session_driver.cc
index 91f3358..5a59853 100644
--- a/src/cobalt/webdriver/session_driver.cc
+++ b/src/cobalt/webdriver/session_driver.cc
@@ -28,6 +28,9 @@
 // Default page-load timeout.
 const int kPageLoadTimeoutInSeconds = 30;
 
+// Max retries for the "can_retry" CommandResult case.
+const int kMaxRetries = 5;
+
 protocol::LogEntry::LogLevel SeverityToLogLevel(int severity) {
   switch (severity) {
     case logging::LOG_INFO:
@@ -82,7 +85,11 @@
 }
 
 util::CommandResult<void> SessionDriver::Navigate(const GURL& url) {
-  util::CommandResult<void> result = window_driver_->Navigate(url);
+  int retries = 0;
+  util::CommandResult<void> result;
+  do {
+    result = window_driver_->Navigate(url);
+  } while (result.can_retry() && (retries++ < kMaxRetries));
   if (result.is_success()) {
     // TODO: Use timeout as specified by the webdriver client.
     wait_for_navigation_.Run(
diff --git a/src/cobalt/webdriver/util/call_on_message_loop.h b/src/cobalt/webdriver/util/call_on_message_loop.h
index f3af96f..c2a19d2 100644
--- a/src/cobalt/webdriver/util/call_on_message_loop.h
+++ b/src/cobalt/webdriver/util/call_on_message_loop.h
@@ -123,24 +123,20 @@
 }
 
 // Tries to call |callback| on messageloop |message_loop_proxy|,
-// retrying a few times if the WebModule thread appears to have gone
-// away (perhaps because of navigation). If failure persists,
-// returns a CommandResult of |window_disappeared_code|.
+// but returns a CommandResult of |window_disappeared_code| if the
+// message loop has shut down. This can happen if a WebModule shuts
+// down due to a page navigation.
 template <typename ReturnValue>
-util::CommandResult<ReturnValue> CallOnMessageLoopWithRetry(
+util::CommandResult<ReturnValue> CallOnMessageLoop(
     const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
     const base::Callback<util::CommandResult<ReturnValue>(void)>& callback,
     protocol::Response::StatusCode window_disappeared_code) {
   util::CommandResult<ReturnValue> result;
-
-  const int kRetryAttempts = 5;
-  bool success = false;
-  for (int i = 0; !success && i < kRetryAttempts; i++) {
-    success = TryCallOnMessageLoop(message_loop_proxy, callback, &result);
-  }
+  bool success = TryCallOnMessageLoop(message_loop_proxy, callback, &result);
 
   if (!success) {
-    result = util::CommandResult<ReturnValue>(window_disappeared_code);
+    result =
+        util::CommandResult<ReturnValue>(window_disappeared_code, "", true);
   }
   return result;
 }
diff --git a/src/cobalt/webdriver/util/command_result.h b/src/cobalt/webdriver/util/command_result.h
index d1254c7..8944d4d 100644
--- a/src/cobalt/webdriver/util/command_result.h
+++ b/src/cobalt/webdriver/util/command_result.h
@@ -32,12 +32,17 @@
  public:
   CommandResult() : status_code_(protocol::Response::kUnknownError) {}
   explicit CommandResult(protocol::Response::StatusCode status)
-      : status_code_(status) {}
+      : status_code_(status), can_retry_(false) {}
   CommandResult(protocol::Response::StatusCode status,
                 const std::string& message)
-      : status_code_(status), error_message_(message) {}
+      : status_code_(status), error_message_(message), can_retry_(false) {}
+  CommandResult(protocol::Response::StatusCode status,
+                const std::string& message, bool can_retry)
+      : status_code_(status), error_message_(message), can_retry_(can_retry) {}
   explicit CommandResult(const T& result)
-      : status_code_(protocol::Response::kSuccess), result_(result) {}
+      : status_code_(protocol::Response::kSuccess),
+        result_(result),
+        can_retry_(false) {}
 
   bool is_success() const {
     return status_code_ == protocol::Response::kSuccess;
@@ -45,11 +50,16 @@
   protocol::Response::StatusCode status_code() const { return status_code_; }
   const T& result() const { return result_.value(); }
   std::string error_message() const { return error_message_.value_or(""); }
+  // Returns true if this result occurred due to a transient issue,
+  // such as the WebModule going away. Retrying w/ a new WebModule
+  // may succeed.
+  bool can_retry() const { return can_retry_; }
 
  private:
   protocol::Response::StatusCode status_code_;
   base::optional<T> result_;
   base::optional<std::string> error_message_;
+  bool can_retry_;
 };
 
 template <>
@@ -57,20 +67,28 @@
  public:
   CommandResult() : status_code_(protocol::Response::kUnknownError) {}
   explicit CommandResult(protocol::Response::StatusCode status)
-      : status_code_(status) {}
+      : status_code_(status), can_retry_(false) {}
   CommandResult(protocol::Response::StatusCode status,
                 const std::string& message)
-      : status_code_(status), error_message_(message) {}
+      : status_code_(status), error_message_(message), can_retry_(false) {}
+  CommandResult(protocol::Response::StatusCode status,
+                const std::string& message, bool can_retry)
+      : status_code_(status), error_message_(message), can_retry_(can_retry) {}
 
   bool is_success() const {
     return status_code_ == protocol::Response::kSuccess;
   }
   protocol::Response::StatusCode status_code() const { return status_code_; }
   std::string error_message() const { return error_message_.value_or(""); }
+  // Returns true if this result occurred due to a transient issue,
+  // such as the WebModule going away. Retrying w/ a new WebModule
+  // may succeed.
+  bool can_retry() const { return can_retry_; }
 
  private:
   protocol::Response::StatusCode status_code_;
   base::optional<std::string> error_message_;
+  bool can_retry_;
 };
 
 }  // namespace util
diff --git a/src/cobalt/webdriver/util/dispatch_command_factory.h b/src/cobalt/webdriver/util/dispatch_command_factory.h
index 1e45e4b..cfed299 100644
--- a/src/cobalt/webdriver/util/dispatch_command_factory.h
+++ b/src/cobalt/webdriver/util/dispatch_command_factory.h
@@ -122,6 +122,9 @@
 template <class DriverClassT>
 class DispatchCommandFactory
     : public base::RefCounted<DispatchCommandFactory<DriverClassT> > {
+  // Max retries for the "can_retry" CommandResult case.
+  static const int kMaxRetries = 5;
+
  public:
   // Typedef'd for less verbose code.
   typedef WebDriverDispatcher::CommandResultHandler CommandResultHandler;
@@ -220,7 +223,11 @@
         DriverClassT* driver, const base::Value* parameters,
         CommandResultHandler* result_handler) {
       // Ignore parameters.
-      util::CommandResult<R> command_result = driver_command.Run(driver);
+      int retries = 0;
+      util::CommandResult<R> command_result;
+      do {
+        command_result = driver_command.Run(driver);
+      } while (command_result.can_retry() && (retries++ < kMaxRetries));
       internal::ReturnResponse(session_id, command_result, result_handler);
     }
 
@@ -245,8 +252,11 @@
         result_handler->SendInvalidRequestResponse(
             WebDriverDispatcher::CommandResultHandler::kInvalidParameters, "");
       } else {
-        util::CommandResult<R> command_result =
-            driver_command.Run(driver, param.value());
+        int retries = 0;
+        util::CommandResult<R> command_result;
+        do {
+          command_result = driver_command.Run(driver, param.value());
+        } while (command_result.can_retry() && (retries++ < kMaxRetries));
         internal::ReturnResponse(session_id, command_result, result_handler);
       }
     }
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc
index 30c1415..b23abc2 100644
--- a/src/cobalt/webdriver/window_driver.cc
+++ b/src/cobalt/webdriver/window_driver.cc
@@ -162,7 +162,7 @@
 
 util::CommandResult<void> WindowDriver::Navigate(const GURL& url) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::NavigateInternal, base::Unretained(this), url),
       protocol::Response::kNoSuchWindow);
@@ -190,7 +190,7 @@
     const protocol::SearchStrategy& strategy) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::FindElementsInternal<protocol::ElementId>,
                  base::Unretained(this), strategy),
@@ -200,7 +200,7 @@
 util::CommandResult<std::vector<protocol::ElementId> >
 WindowDriver::FindElements(const protocol::SearchStrategy& strategy) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::FindElementsInternal<ElementIdVector>,
                  base::Unretained(this), strategy),
@@ -226,7 +226,7 @@
 
   SyncExecuteResultHandler result_handler;
 
-  CommandResult result = util::CallOnMessageLoopWithRetry(
+  CommandResult result = util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::ExecuteScriptInternal, base::Unretained(this),
                  script, base::nullopt, &result_handler),
@@ -249,7 +249,7 @@
   const base::TimeDelta kDefaultAsyncTimeout =
       base::TimeDelta::FromMilliseconds(0);
   AsyncExecuteResultHandler result_handler;
-  CommandResult result = util::CallOnMessageLoopWithRetry(
+  CommandResult result = util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::ExecuteScriptInternal, base::Unretained(this),
                  script, kDefaultAsyncTimeout, &result_handler),
@@ -274,7 +274,7 @@
   Keyboard::TranslateToKeyEvents(keys.utf8_keys(), Keyboard::kKeepModifiers,
                                  events.get());
   // Dispatch the keyboard events.
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       window_message_loop_,
       base::Bind(&WindowDriver::SendKeysInternal, base::Unretained(this),
                  base::Passed(&events)),
@@ -282,7 +282,7 @@
 }
 
 util::CommandResult<protocol::ElementId> WindowDriver::GetActiveElement() {
-  return util::CallOnMessageLoopWithRetry(
+  return util::CallOnMessageLoop(
       window_message_loop_, base::Bind(&WindowDriver::GetActiveElementInternal,
                                        base::Unretained(this)),
       protocol::Response::kNoSuchWindow);
@@ -330,10 +330,10 @@
 util::CommandResult<void> WindowDriver::AddCookie(
     const protocol::Cookie& cookie) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return util::CallOnMessageLoopWithRetry(
-      window_message_loop_, base::Bind(&WindowDriver::AddCookieInternal,
-                                       base::Unretained(this), cookie),
-      protocol::Response::kNoSuchWindow);
+  return util::CallOnMessageLoop(window_message_loop_,
+                                 base::Bind(&WindowDriver::AddCookieInternal,
+                                            base::Unretained(this), cookie),
+                                 protocol::Response::kNoSuchWindow);
 }
 
 protocol::ElementId WindowDriver::ElementToId(
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase.py b/src/cobalt/webdriver_benchmarks/tv_testcase.py
index 57a7b77..c9a16ca 100644
--- a/src/cobalt/webdriver_benchmarks/tv_testcase.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase.py
@@ -41,6 +41,11 @@
 BASE_PARAMS = {"env_forcedOffAllExperiments": True}
 PAGE_LOAD_WAIT_SECONDS = 30
 LAYOUT_TIMEOUT_SECONDS = 5
+# Today, Cobalt's WebDriver has a race that
+# can leave the former page's DOM visible after a navigate.
+# As a workaround, sleep for a bit
+# b/33275371
+COBALT_POST_NAVIGATE_SLEEP_SECONDS = 5
 
 
 def _percentile(results, percentile):
@@ -176,6 +181,7 @@
     parsed_url[4] = urlencode(query_dict, doseq=True)
     final_url = urlparse.urlunparse(parsed_url)
     self.get_webdriver().get(final_url)
+    time.sleep(COBALT_POST_NAVIGATE_SLEEP_SECONDS)
 
   def load_tv(self, label=None, additional_query_params=None):
     """Loads the main TV page and waits for it to display.
diff --git a/src/nb/analytics/memory_tracker.cc b/src/nb/analytics/memory_tracker.cc
index 8cb7664..56471dd 100644
--- a/src/nb/analytics/memory_tracker.cc
+++ b/src/nb/analytics/memory_tracker.cc
@@ -31,11 +31,37 @@
   return t;
 }
 
+
+MemoryStats GetProcessMemoryStats() {
+  MemoryStats memory_stats;
+
+  memory_stats.total_cpu_memory = SbSystemGetTotalCPUMemory();
+  memory_stats.used_cpu_memory = SbSystemGetUsedCPUMemory();
+
+  if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+    int64_t used_gpu_memory = SbSystemGetUsedGPUMemory();
+    memory_stats.total_gpu_memory = SbSystemGetTotalGPUMemory();
+    memory_stats.used_gpu_memory = SbSystemGetUsedGPUMemory();
+  }
+  return memory_stats;
+}
+
 nb::scoped_ptr<MemoryTrackerPrintThread>
 CreateDebugPrintThread(MemoryTracker* memory_tracker) {
   return nb::scoped_ptr<MemoryTrackerPrintThread>(
      new MemoryTrackerPrintThread(memory_tracker));
 }
 
+nb::scoped_ptr<MemoryTrackerPrintCSVThread>
+CreateDebugPrintCSVThread(MemoryTracker* memory_tracker,
+                          int sample_interval_ms,
+                          int total_sampling_time_ms) {
+  return nb::scoped_ptr<MemoryTrackerPrintCSVThread>(
+      new MemoryTrackerPrintCSVThread(
+          memory_tracker,
+          sample_interval_ms,
+          total_sampling_time_ms));
+}
+
 }  // namespace analytics
 }  // namespace nb
diff --git a/src/nb/analytics/memory_tracker.h b/src/nb/analytics/memory_tracker.h
index 4884c89..7d1c332 100644
--- a/src/nb/analytics/memory_tracker.h
+++ b/src/nb/analytics/memory_tracker.h
@@ -28,10 +28,22 @@
 
 class MemoryTracker;
 class MemoryTrackerPrintThread;
+class MemoryTrackerPrintCSVThread;
 class AllocationVisitor;
 class AllocationGroup;
 class AllocationRecord;
 
+struct MemoryStats {
+  MemoryStats() : total_cpu_memory(0), used_cpu_memory(0),
+                  total_gpu_memory(0), used_gpu_memory(0) {}
+  int64_t total_cpu_memory;
+  int64_t used_cpu_memory;
+  int64_t total_gpu_memory;
+  int64_t used_gpu_memory;
+};
+
+MemoryStats GetProcessMemoryStats();
+
 // Creates a MemoryTracker instance that implements the
 //  MemoryTracker. Once the instance is created it can begin tracking
 //  system allocations by calling InstallGlobalTrackingHooks().
@@ -142,6 +154,15 @@
 scoped_ptr<MemoryTrackerPrintThread>
     CreateDebugPrintThread(MemoryTracker* memory_tracker);
 
+// Creates a SimpleThread that will output the state of the memory
+// periodically. Start()/Cancel()/Join() are called AUTOMATICALLY with
+// this object. Start() is on the returned thread before it is returned.
+// Join() is automatically called on destruction.
+scoped_ptr<MemoryTrackerPrintCSVThread>
+    CreateDebugPrintCSVThread(MemoryTracker* memory_tracker,
+                              int sample_interval_ms,
+                              int total_sampling_time_ms);
+
 }  // namespace analytics
 }  // namespace nb
 
diff --git a/src/nb/analytics/memory_tracker_impl.cc b/src/nb/analytics/memory_tracker_impl.cc
index 3a9bdf4..a4a8c89 100644
--- a/src/nb/analytics/memory_tracker_impl.cc
+++ b/src/nb/analytics/memory_tracker_impl.cc
@@ -16,15 +16,66 @@
 
 #include "nb/analytics/memory_tracker_impl.h"
 
+#include <cstring>
 #include <iomanip>
+#include <iterator>
 #include <sstream>
 
 #include "nb/atomic.h"
-#include "starboard/log.h"
 #include "starboard/atomic.h"
+#include "starboard/log.h"
+#include "starboard/time.h"
 
 namespace nb {
 namespace analytics {
+namespace {
+// NoMemoryTracking will disable memory tracking while in the current scope of
+// execution. When the object is destroyed it will reset the previous state
+// of allocation tracking.
+// Example:
+//   void Foo() {
+//     NoMemoryTracking no_memory_tracking_in_scope;
+//     int* ptr = new int();  // ptr is not tracked.
+//     delete ptr;
+//     return;    // Previous memory tracking state is restored.
+//   }
+class NoMemoryTracking {
+ public:
+  NoMemoryTracking(MemoryTracker* owner) : owner_(owner) {
+    prev_val_ = owner_->IsMemoryTrackingEnabled();
+    owner_->SetMemoryTrackingEnabled(false);
+  }
+  ~NoMemoryTracking() { owner_->SetMemoryTrackingEnabled(prev_val_); }
+
+ private:
+  bool prev_val_;
+  MemoryTracker* owner_;
+};
+
+// This is a simple algorithm to remove the "needle" from the haystack. Note
+// that this function is simple and not well optimized.
+std::string RemoveString(const std::string& haystack, const char* needle) {

+  const size_t NOT_FOUND = std::string::npos;

+

+  // Base case. No modification needed.

+  size_t pos = haystack.find(needle);

+  if (pos == NOT_FOUND) {

+    return haystack;

+  }

+  const size_t n = strlen(needle);

+  std::string output;

+  output.reserve(haystack.size());

+

+  // Copy string, omitting the portion containing the "needle".

+  std::copy(haystack.begin(), haystack.begin() + pos,

+            std::back_inserter(output));

+  std::copy(haystack.begin() + pos + n, haystack.end(),

+            std::back_inserter(output));

+

+  // Recursively remove same needle in haystack.

+  return RemoveString(output, needle);

+}
+}  // namespace
 
 SbMemoryReporter* MemoryTrackerImpl::GetMemoryReporter() {
   return &sb_memory_tracker_;
@@ -197,7 +248,7 @@
   // We might do something more interesting with UnMapMemory calls later.
   OnDealloc(context, memory);
 }
-

+
 void MemoryTrackerImpl::OnPushAllocationGroup(
     void* context,
     NbMemoryScopeInfo* memory_scope_info) {
@@ -346,15 +397,15 @@
       prev_group_name = "none";
     }
 
-    if (!added) {

-      std::stringstream ss;

-      ss << "\nUnexpected condition, previous allocation was not removed:\n"

-         << "\tprevious alloc group: " << prev_group_name << "\n"

-         << "\tnew alloc group: " << group->name() << "\n"

-         << "\tprevious size: " << unexpected_alloc.size << "\n"

-         << "\tnew size: " << size << "\n";

-

-      SbLogRaw(ss.str().c_str());

+    if (!added) {
+      std::stringstream ss;
+      ss << "\nUnexpected condition, previous allocation was not removed:\n"
+         << "\tprevious alloc group: " << prev_group_name << "\n"
+         << "\tnew alloc group: " << group->name() << "\n"
+         << "\tprevious size: " << unexpected_alloc.size << "\n"
+         << "\tnew size: " << size << "\n";
+
+      SbLogRaw(ss.str().c_str());
     }
   }
   return added;
@@ -448,19 +499,8 @@
 }
 
 void MemoryTrackerPrintThread::Run() {
-  struct NoMemTracking {
-    NoMemTracking(MemoryTracker* owner) : owner_(owner) {
-      prev_val_ = owner_->IsMemoryTrackingEnabled();
-      owner_->SetMemoryTrackingEnabled(false);
-    }
-    ~NoMemTracking() { owner_->SetMemoryTrackingEnabled(prev_val_); }
-
-    bool prev_val_;
-    MemoryTracker* owner_;
-  };
-
   while (!finished_.load()) {
-    NoMemTracking no_mem_tracking_in_this_scope(memory_tracker_);
+    NoMemoryTracking no_mem_tracking_in_this_scope(memory_tracker_);
 
     // std::map<std::string, const AllocationGroup*> output;
     // typedef std::map<std::string, const AllocationGroup*>::const_iterator
@@ -539,5 +579,258 @@
   }
 }
 
+MemoryTrackerPrintCSVThread::MemoryTrackerPrintCSVThread(
+    MemoryTracker* memory_tracker,
+    int sampling_interval_ms,
+    int sampling_time_ms)
+    : SimpleThread("MemoryTrackerPrintCSVThread"),
+      memory_tracker_(memory_tracker),
+      sample_interval_ms_(sampling_interval_ms),
+      sampling_time_ms_(sampling_time_ms),
+      start_time_(SbTimeGetNow()) {
+  Start();
+}
+
+
+MemoryTrackerPrintCSVThread::~MemoryTrackerPrintCSVThread() {
+  Cancel();
+  Join();
+}
+
+void MemoryTrackerPrintCSVThread::Cancel() {
+  canceled_.store(true);
+}
+
+std::string MemoryTrackerPrintCSVThread::ToCsvString(
+    const MapAllocationSamples& samples_in) {
+  typedef MapAllocationSamples Map;
+  typedef Map::const_iterator MapIt;
+
+  const char QUOTE[] = "\"";
+  const char DELIM[] = ",";
+  const char NEW_LINE[] = "\n";
+
+  size_t largest_sample_size = 0;
+  size_t smallest_sample_size = INT_MAX;
+
+  // Sanitize samples_in and store as samples.
+  MapAllocationSamples samples;
+  for (MapIt it = samples_in.begin(); it != samples_in.end(); ++it) {
+    std::string name = it->first;
+    const AllocationSamples& value = it->second;
+
+    if (value.allocated_bytes_.size() != value.number_allocations_.size()) {
+      SB_NOTREACHED() << "Error at " << __FILE__ << ":" << __LINE__;
+      return "ERROR";
+    }
+
+    const size_t n = value.allocated_bytes_.size();
+    if (n > largest_sample_size) {
+      largest_sample_size = n;
+    }
+    if (n < smallest_sample_size) {
+      smallest_sample_size = n;
+    }
+
+    // Strip out any characters that could make parsing the csv difficult.
+    name = RemoveString(name, QUOTE);
+    name = RemoveString(name, DELIM);
+    name = RemoveString(name, NEW_LINE);
+
+    const bool duplicate_found = (samples.end() != samples.find(name));
+    if (duplicate_found) {
+      SB_NOTREACHED() << "Error, duplicate found for entry: "
+                      << name << NEW_LINE;
+    }
+    // Store value as a sanitized sample.
+    samples[name] = value;
+  }
+
+  SB_DCHECK(largest_sample_size == smallest_sample_size);
+
+  std::stringstream ss;
+
+  // Begin output to CSV.
+  // Sometimes we need to skip the CPU memory entry.
+  const MapIt total_cpu_memory_it = samples.find(UntrackedMemoryKey());
+
+  // Preamble
+  ss << NEW_LINE << "//////////////////////////////////////////////";
+  ss << NEW_LINE << "// CSV of bytes / allocation" << NEW_LINE;
+  // HEADER.
+  ss << "Name" << DELIM << QUOTE << "Bytes/Alloc" << QUOTE << NEW_LINE;
+  // DATA.
+  for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+    if (total_cpu_memory_it == it) {
+      continue;
+    }
+
+    const AllocationSamples& samples = it->second;
+    if (samples.allocated_bytes_.empty() ||
+        samples.number_allocations_.empty()) {
+      SB_NOTREACHED() << "Should not be here";
+      return "ERROR";
+    }
+    const int32_t n_allocs = samples.number_allocations_.back();
+    const int64_t n_bytes = samples.allocated_bytes_.back();
+    int bytes_per_alloc = 0;
+    if (n_allocs > 0) {
+      bytes_per_alloc = n_bytes / n_allocs;
+    }
+    const std::string& name = it->first;
+    ss << QUOTE << name << QUOTE << DELIM << bytes_per_alloc << NEW_LINE;
+  }
+  ss << NEW_LINE;
+
+  // Preamble
+  ss << NEW_LINE << "//////////////////////////////////////////////"
+     << NEW_LINE << "// CSV of bytes allocated per region (MB's)."
+     << NEW_LINE << "// Units are in Megabytes. This is designed"
+     << NEW_LINE << "// to be used in a stacked graph." << NEW_LINE;
+
+  // HEADER.
+  for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+    if (total_cpu_memory_it == it) {
+      continue;
+    }
+    const std::string& name = it->first;
+    ss << QUOTE << name << QUOTE << DELIM;
+  }
+  // Save the total for last.
+  if (total_cpu_memory_it != samples.end()) {
+    const std::string& name = total_cpu_memory_it->first;
+    ss << QUOTE << name << QUOTE << DELIM;
+  }
+  ss << NEW_LINE;
+
+  // Print out the values of each of the samples.
+  for (int i = 0; i < smallest_sample_size; ++i) {
+    for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+      if (total_cpu_memory_it == it) {
+        continue;
+      }
+      const int64_t alloc_bytes = it->second.allocated_bytes_[i];
+      // Convert to float megabytes with decimals of precision.
+      double n = alloc_bytes / (1000 * 10);
+      n = n / (100.);
+      ss << n << DELIM;
+    }
+    if (total_cpu_memory_it != samples.end()) {
+      const int64_t alloc_bytes =
+         total_cpu_memory_it->second.allocated_bytes_[i];
+      // Convert to float megabytes with decimals of precision.
+      double n = alloc_bytes / (1000 * 10);
+      n = n / (100.);
+      ss << n << DELIM;
+    }
+    ss << NEW_LINE;
+  }
+
+  ss << NEW_LINE;
+  // Preamble
+  ss << NEW_LINE << "//////////////////////////////////////////////";
+  ss << NEW_LINE << "// CSV of number of allocations per region." << NEW_LINE;
+
+  // HEADER
+  for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+    if (total_cpu_memory_it == it) {
+      continue;
+    }
+    const std::string& name = it->first;
+    ss << QUOTE << name << QUOTE << DELIM;
+  }
+  ss << NEW_LINE;
+  for (int i = 0; i < smallest_sample_size; ++i) {
+    for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+      if (total_cpu_memory_it == it) {
+        continue;
+      }
+      const int64_t n_allocs = it->second.number_allocations_[i];
+      ss << n_allocs << DELIM;
+    }
+    ss << NEW_LINE;
+  }
+  std::string output = ss.str();
+  return output;
+}
+
+const char* MemoryTrackerPrintCSVThread::UntrackedMemoryKey() {
+  return "Untracked Memory";
+}
+
+void MemoryTrackerPrintCSVThread::Run() {
+  NoMemoryTracking no_mem_tracking_in_this_scope(memory_tracker_);
+
+  SbLogRaw("\nMemoryTrackerPrintCSVThread is sampling...\n");
+  int sample_count = 0;
+  MapAllocationSamples map_samples;
+
+  while (!TimeExpiredYet() && !canceled_.load()) {
+    // Sample total memory used by the system.
+    MemoryStats mem_stats = GetProcessMemoryStats();
+    int64_t untracked_used_memory = mem_stats.used_cpu_memory +
+                                    mem_stats.used_gpu_memory;
+
+    std::vector<const AllocationGroup*> vector_output;
+    memory_tracker_->GetAllocationGroups(&vector_output);
+
+    // Sample all known memory scopes.
+    for (int i = 0; i < vector_output.size(); ++i) {
+      const AllocationGroup* group = vector_output[i];
+      const std::string& name = group->name();
+
+      const bool first_creation = map_samples.find(group->name()) ==
+                                  map_samples.end();
+
+      AllocationSamples* new_entry  = &(map_samples[name]);
+
+      // Didn't see it before so create new entry.
+      if (first_creation) {
+        // Make up for lost samples...
+        new_entry->allocated_bytes_.resize(sample_count, 0);
+        new_entry->number_allocations_.resize(sample_count, 0);
+      }
+
+      int32_t num_allocs = - 1;
+      int64_t allocation_bytes = -1;
+      group->GetAggregateStats(&num_allocs, &allocation_bytes);
+
+      new_entry->allocated_bytes_.push_back(allocation_bytes);
+      new_entry->number_allocations_.push_back(num_allocs);
+
+      untracked_used_memory -= allocation_bytes;
+    }
+
+    // Now push in remaining total.
+    AllocationSamples* process_sample = &(map_samples[UntrackedMemoryKey()]);
+    if (untracked_used_memory < 0) {
+      // On some platforms, total GPU memory may not be correctly reported.
+      // However the allocations from the GPU memory may be reported. In this
+      // case untracked_used_memory will go negative. To protect the memory
+      // reporting the untracked_used_memory is set to 0 so that it doesn't
+      // cause an error in reporting.
+      untracked_used_memory = 0;
+    }
+    process_sample->allocated_bytes_.push_back(untracked_used_memory);
+    process_sample->number_allocations_.push_back(-1);
+
+    ++sample_count;
+    SbThreadSleep(kSbTimeMillisecond * sample_interval_ms_);
+  }
+
+  std::string output = ToCsvString(map_samples);
+  SbLogRaw(output.c_str());
+  SbLogFlush();
+  // Prevents the "thread exited code 0" from being interleaved into the
+  // output. This happens if SbLogFlush() is not implemented for the platform.
+  SbThreadSleep(1000 * kSbTimeMillisecond);
+}
+
+bool MemoryTrackerPrintCSVThread::TimeExpiredYet() {
+  const SbTime diff_us = SbTimeGetNow() - start_time_;
+  const bool expired_time = diff_us > (sampling_time_ms_ * kSbTimeMillisecond);
+  return expired_time;
+}
+
 }  // namespace analytics
 }  // namespace nb
diff --git a/src/nb/analytics/memory_tracker_impl.h b/src/nb/analytics/memory_tracker_impl.h
index 1575e7b..1af04aa 100644
--- a/src/nb/analytics/memory_tracker_impl.h
+++ b/src/nb/analytics/memory_tracker_impl.h
@@ -26,6 +26,7 @@
 #include "starboard/memory_reporter.h"
 #include "starboard/memory.h"
 #include "starboard/mutex.h"
+#include "starboard/time.h"
 
 namespace nb {
 namespace analytics {
@@ -177,7 +178,7 @@
 
 // Start() is called when this object is created, and Cancel() & Join() are
 // called during destruction.
-class MemoryTrackerPrintThread : private SimpleThread {
+class MemoryTrackerPrintThread : public SimpleThread {
  public:
   MemoryTrackerPrintThread(MemoryTracker* memory_tracker);
   virtual ~MemoryTrackerPrintThread() SB_OVERRIDE;
@@ -191,6 +192,41 @@
   MemoryTracker* memory_tracker_;
 };
 
+// Generates CSV values of the engine.
+// There are three sections of data including:
+//   1. average bytes / alloc
+//   2. # Bytes allocated per memory scope.
+//   3. # Allocations per memory scope.
+// This data can be pasted directly into a Google spreadsheet and visualized.
+// Note that this thread will implicitly call Start() is called during
+// construction and Cancel() & Join() during destruction.
+class MemoryTrackerPrintCSVThread : public SimpleThread {
+ public:
+  MemoryTrackerPrintCSVThread(MemoryTracker* memory_tracker,
+                              int sampling_interval_ms,
+                              int sampling_time_ms);
+  virtual ~MemoryTrackerPrintCSVThread() SB_OVERRIDE;
+
+  // Overridden so that the thread can exit gracefully.
+  virtual void Cancel() SB_OVERRIDE;
+  virtual void Run() SB_OVERRIDE;
+ private:
+  struct AllocationSamples {
+    std::vector<int32_t> number_allocations_;
+    std::vector<int64_t> allocated_bytes_;
+  };
+  typedef std::map<std::string, AllocationSamples> MapAllocationSamples;
+  static std::string ToCsvString(const MapAllocationSamples& samples);
+  static const char* UntrackedMemoryKey();
+  bool TimeExpiredYet();
+
+  MemoryTracker* memory_tracker_;
+  const int sample_interval_ms_;
+  const int sampling_time_ms_;
+  SbTime start_time_;
+  atomic_bool canceled_;
+};
+
 }  // namespace analytics
 }  // namespace nb
 
diff --git a/src/nb/memory_scope.h b/src/nb/memory_scope.h
index d7d37bf..72e1ddc 100644
--- a/src/nb/memory_scope.h
+++ b/src/nb/memory_scope.h
@@ -124,7 +124,7 @@
   // When true, if cached_handle_ is 0 then an object may be created that
   // represents the fields of this object. The handle that represents this
   // cached object is then placed in cached_hanlde_.
-  const bool allows_caching_;
+  bool allows_caching_;
 };
 
 // NbPopMemoryScopeOnScopeEnd is only allowed for C++ builds.
diff --git a/src/net/base/data_url.cc b/src/net/base/data_url.cc
index b7309cb..53a5ea8 100644
--- a/src/net/base/data_url.cc
+++ b/src/net/base/data_url.cc
@@ -13,6 +13,7 @@
 #include "base/string_split.h"
 #include "base/string_util.h"
 #include "googleurl/src/gurl.h"
+#include "nb/memory_scope.h"
 #include "net/base/escape.h"
 
 namespace net {
@@ -20,6 +21,7 @@
 // static
 bool DataURL::Parse(const GURL& url, std::string* mime_type,
                     std::string* charset, std::string* data) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(mime_type->empty());
   DCHECK(charset->empty());
   std::string::const_iterator begin = url.spec().begin();
diff --git a/src/net/base/host_resolver_impl.cc b/src/net/base/host_resolver_impl.cc
index 11ccd9f..9c1ac57 100644
--- a/src/net/base/host_resolver_impl.cc
+++ b/src/net/base/host_resolver_impl.cc
@@ -44,6 +44,7 @@
 #include "net/dns/dns_protocol.h"
 #include "net/dns/dns_response.h"
 #include "net/dns/dns_transaction.h"
+#include "nb/memory_scope.h"
 
 #if defined(OS_WIN)
 #include "net/base/winsock_init.h"
@@ -580,6 +581,7 @@
   ~ProcTask() {}
 
   void StartLookupAttempt() {
+    TRACK_MEMORY_SCOPE("Network");
     DCHECK(origin_loop_->BelongsToCurrentThread());
     base::TimeTicks start_time = base::TimeTicks::Now();
     ++attempt_number_;
diff --git a/src/net/base/host_resolver_proc.cc b/src/net/base/host_resolver_proc.cc
index 8950f5b..a4512e9 100644
--- a/src/net/base/host_resolver_proc.cc
+++ b/src/net/base/host_resolver_proc.cc
@@ -12,6 +12,7 @@
 #include "net/base/dns_reloader.h"
 #include "net/base/net_errors.h"
 #include "net/base/sys_addrinfo.h"
+#include "nb/memory_scope.h"
 
 #if defined(OS_STARBOARD)
 #include "starboard/socket.h"
@@ -133,6 +134,7 @@
                            HostResolverFlags host_resolver_flags,
                            AddressList* addrlist,
                            int* os_error) {
+  TRACK_MEMORY_SCOPE("Network");
   if (os_error)
     *os_error = 0;
 
diff --git a/src/net/base/net_errors.h b/src/net/base/net_errors.h
index 95a81e9..43cffab 100644
--- a/src/net/base/net_errors.h
+++ b/src/net/base/net_errors.h
@@ -49,7 +49,7 @@
 NET_EXPORT Error MapSocketError(SbSocketError error);
 
 // Gets the last socket error as a net error.
-SB_C_INLINE Error MapLastSocketError(SbSocket socket) {
+static SB_C_INLINE Error MapLastSocketError(SbSocket socket) {
   return MapSocketError(SbSocketGetLastError(socket));
 }
 
@@ -57,7 +57,7 @@
 NET_EXPORT Error MapSystemError(SbSystemError error);
 
 // Gets the last system error as a net error.
-SB_C_INLINE Error MapLastSystemError() {
+static SB_C_INLINE Error MapLastSystemError() {
   return MapSystemError(SbSystemGetLastError());
 }
 
diff --git a/src/net/http/http_stream_factory_impl_job.cc b/src/net/http/http_stream_factory_impl_job.cc
index 77422ce..9554ce6 100644
--- a/src/net/http/http_stream_factory_impl_job.cc
+++ b/src/net/http/http_stream_factory_impl_job.cc
@@ -12,6 +12,7 @@
 #include "base/stringprintf.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "nb/memory_scope.h"
 #include "net/base/connection_type_histograms.h"
 #include "net/base/net_log.h"
 #include "net/base/net_util.h"
@@ -267,6 +268,7 @@
 }
 
 void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(stream_.get());
   DCHECK(!IsPreconnecting());
   if (IsOrphaned()) {
diff --git a/src/net/net.gyp b/src/net/net.gyp
index 3d7b9d4..d13a159 100644
--- a/src/net/net.gyp
+++ b/src/net/net.gyp
@@ -57,6 +57,7 @@
         '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
         '../googleurl/googleurl.gyp:googleurl',
         '../crypto/crypto.gyp:crypto',
+        '../nb/nb.gyp:nb',
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/icu/icu.gyp:icuuc',
         '../third_party/zlib/zlib.gyp:zlib',
diff --git a/src/net/socket/client_socket_handle.cc b/src/net/socket/client_socket_handle.cc
index 20ab672..cffb902 100644
--- a/src/net/socket/client_socket_handle.cc
+++ b/src/net/socket/client_socket_handle.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/metrics/histogram.h"
 #include "base/logging.h"
+#include "nb/memory_scope.h"
 #include "net/base/net_errors.h"
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/client_socket_pool_histograms.h"
@@ -104,6 +105,7 @@
 }
 
 void ClientSocketHandle::OnIOComplete(int result) {
+  TRACK_MEMORY_SCOPE("Network");
   CompletionCallback callback = user_callback_;
   user_callback_.Reset();
   HandleInitCompletion(result);
@@ -111,6 +113,7 @@
 }
 
 void ClientSocketHandle::HandleInitCompletion(int result) {
+  TRACK_MEMORY_SCOPE("Network");
   CHECK_NE(ERR_IO_PENDING, result);
   if (result != OK) {
     if (!socket_.get())
diff --git a/src/net/socket/tcp_client_socket_starboard.cc b/src/net/socket/tcp_client_socket_starboard.cc
index 48d76b5..c970ac7 100644
--- a/src/net/socket/tcp_client_socket_starboard.cc
+++ b/src/net/socket/tcp_client_socket_starboard.cc
@@ -23,6 +23,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/string_util.h"
 #include "base/stringprintf.h"
+#include "nb/memory_scope.h"
 #include "net/base/address_family.h"
 #include "net/base/connection_type_histograms.h"
 #include "net/base/io_buffer.h"
@@ -154,6 +155,7 @@
 }
 
 int TCPClientSocketStarboard::Connect(const CompletionCallback& callback) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(CalledOnValidThread());
 
   // If this socket is already valid, then just return OK.
@@ -186,6 +188,7 @@
 // pretty much cribbed directly from TCPClientSocketLibevent and/or
 // TCPClientSocketWin, take your pick, they're identical
 int TCPClientSocketStarboard::DoConnectLoop(int result) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
 
   int rv = result;
@@ -211,6 +214,7 @@
 }
 
 int TCPClientSocketStarboard::DoConnect() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_GE(current_address_index_, 0);
   DCHECK_LT(current_address_index_, static_cast<int>(addresses_.size()));
 
@@ -257,6 +261,7 @@
 }
 
 int TCPClientSocketStarboard::DoConnectComplete(int result) {
+  TRACK_MEMORY_SCOPE("Network");
   // Log the end of this attempt (and any OS error it threw).
   int error = connect_error_;
   connect_error_ = OK;
@@ -287,6 +292,7 @@
 }
 
 void TCPClientSocketStarboard::DidCompleteConnect() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
 
   connect_error_ = SbSocketIsConnected(socket_) ? OK : ERR_FAILED;
@@ -298,6 +304,7 @@
 }
 
 void TCPClientSocketStarboard::LogConnectCompletion(int net_error) {
+  TRACK_MEMORY_SCOPE("Network");
   if (net_error == OK)
     UpdateConnectionTypeHistograms(CONNECTION_ANY);
 
@@ -422,6 +429,7 @@
 int TCPClientSocketStarboard::Read(IOBuffer* buf,
                                    int buf_len,
                                    const CompletionCallback& callback) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(SbSocketIsValid(socket_));
   DCHECK(!waiting_connect());
   DCHECK(!waiting_read_);
@@ -459,6 +467,7 @@
 }
 
 void TCPClientSocketStarboard::DidCompleteRead() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(waiting_read_);
   int bytes_read =
       SbSocketReceiveFrom(socket_, read_buf_->data(), read_buf_len_, NULL);
@@ -485,6 +494,7 @@
 }
 
 void TCPClientSocketStarboard::DoReadCallback(int rv) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_NE(rv, ERR_IO_PENDING);
 
   // since Run may result in Read being called, clear read_callback_ up front.
@@ -496,6 +506,7 @@
 int TCPClientSocketStarboard::Write(IOBuffer* buf,
                                     int buf_len,
                                     const CompletionCallback& callback) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(SbSocketIsValid(socket_));
   DCHECK(!waiting_connect());
   DCHECK(!waiting_write_);
@@ -535,6 +546,7 @@
 }
 
 void TCPClientSocketStarboard::DidCompleteWrite() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(waiting_write_);
   int nwrite =
       SbSocketSendTo(socket_, write_buf_->data(), write_buf_len_, NULL);
@@ -560,6 +572,7 @@
 }
 
 void TCPClientSocketStarboard::DoWriteCallback(int rv) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_NE(rv, ERR_IO_PENDING);
 
   // since Run may result in Write being called, clear write_callback_ up front.
@@ -569,22 +582,27 @@
 }
 
 bool TCPClientSocketStarboard::SetReceiveBufferSize(int32 size) {
+  TRACK_MEMORY_SCOPE("Network");
   return SbSocketSetReceiveBufferSize(socket_, size);
 }
 
 bool TCPClientSocketStarboard::SetSendBufferSize(int32 size) {
+  TRACK_MEMORY_SCOPE("Network");
   return SbSocketSetSendBufferSize(socket_, size);
 }
 
 bool TCPClientSocketStarboard::SetKeepAlive(bool enable, int delay) {
+  TRACK_MEMORY_SCOPE("Network");
   return SbSocketSetTcpKeepAlive(socket_, enable, delay);
 }
 
 bool TCPClientSocketStarboard::SetNoDelay(bool no_delay) {
+  TRACK_MEMORY_SCOPE("Network");
   return SbSocketSetTcpNoDelay(socket_, no_delay);
 }
 
 bool TCPClientSocketStarboard::SetWindowScaling(bool enable) {
+  TRACK_MEMORY_SCOPE("Network");
   return SbSocketSetTcpWindowScaling(socket_, enable);
 }
 
diff --git a/src/net/udp/udp_listen_socket.cc b/src/net/udp/udp_listen_socket.cc
index 848290b..82fdfd9 100644
--- a/src/net/udp/udp_listen_socket.cc
+++ b/src/net/udp/udp_listen_socket.cc
@@ -33,6 +33,7 @@
 #include "base/sys_byteorder.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
+#include "nb/memory_scope.h"
 #include "net/base/net_util.h"
 #if defined(OS_STARBOARD)
 #include "starboard/socket.h"
@@ -87,12 +88,14 @@
 
 void UDPListenSocket::SendTo(const IPEndPoint& address,
                              const std::string& str) {
+  TRACK_MEMORY_SCOPE("Network");
   SendTo(address, str.data(), static_cast<int>(str.length()));
 }
 
 void UDPListenSocket::SendTo(const IPEndPoint& address,
                              const char* bytes,
                              int len) {
+  TRACK_MEMORY_SCOPE("Network");
 #if defined(OS_STARBOARD)
   SbSocketAddress dst_addr;
   if (!address.ToSbSocketAddress(&dst_addr)) {
@@ -130,6 +133,7 @@
 }
 
 void UDPListenSocket::Read() {
+  TRACK_MEMORY_SCOPE("Network");
   if (buffer_ == NULL) {
     // +1 for null termination
     buffer_.reset(new char[kUdpMaxPacketSize + 1]);
@@ -192,6 +196,7 @@
 }
 
 void UDPListenSocket::WatchSocket() {
+  TRACK_MEMORY_SCOPE("Network");
 #if defined(OS_STARBOARD)
   MessageLoopForIO::current()->Watch(
       socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
diff --git a/src/net/url_request/url_fetcher_core.cc b/src/net/url_request/url_fetcher_core.cc
index ea36c74..82976da 100644
--- a/src/net/url_request/url_fetcher_core.cc
+++ b/src/net/url_request/url_fetcher_core.cc
@@ -13,6 +13,7 @@
 #include "base/stl_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/tracked_objects.h"
+#include "nb/memory_scope.h"
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -42,6 +43,7 @@
 URLFetcherCore::Registry::~Registry() {}
 
 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(!ContainsKey(fetchers_, core));
   fetchers_.insert(core);
 }
@@ -75,6 +77,7 @@
 
 void URLFetcherCore::FileWriter::CreateFileAtPath(
     const FilePath& file_path) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
   DCHECK(file_task_runner_.get());
   base::FileUtilProxy::CreateOrOpen(
@@ -87,6 +90,7 @@
 }
 
 void URLFetcherCore::FileWriter::CreateTempFile() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
   DCHECK(file_task_runner_.get());
   base::FileUtilProxy::CreateTemporary(
@@ -97,6 +101,7 @@
 }
 
 void URLFetcherCore::FileWriter::WriteBuffer(int num_bytes) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   // Start writing to the file by setting the initial state
@@ -110,6 +115,7 @@
 void URLFetcherCore::FileWriter::ContinueWrite(
     base::PlatformFileError error_code,
     int bytes_written) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   if (file_handle_ == base::kInvalidPlatformFileValue) {
@@ -154,6 +160,7 @@
 }
 
 void URLFetcherCore::FileWriter::DisownFile() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   // Disowning is done by the delegate's OnURLFetchComplete method.
@@ -165,6 +172,7 @@
 }
 
 void URLFetcherCore::FileWriter::CloseFileAndCompleteRequest() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   if (file_handle_ != base::kInvalidPlatformFileValue) {
@@ -177,6 +185,7 @@
 }
 
 void URLFetcherCore::FileWriter::CloseAndDeleteFile() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   if (file_handle_ == base::kInvalidPlatformFileValue) {
@@ -193,6 +202,7 @@
 
 void URLFetcherCore::FileWriter::DeleteFile(
     base::PlatformFileError error_code) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
   if (file_path_.empty())
     return;
@@ -209,6 +219,7 @@
     base::PlatformFileError error_code,
     base::PassPlatformFile file_handle,
     bool created) {
+  TRACK_MEMORY_SCOPE("Network");
   DidCreateFileInternal(file_path, error_code, file_handle);
 }
 
@@ -216,6 +227,7 @@
     base::PlatformFileError error_code,
     base::PassPlatformFile file_handle,
     const FilePath& file_path) {
+  TRACK_MEMORY_SCOPE("Network");
   DidCreateFileInternal(file_path, error_code, file_handle);
 }
 
@@ -223,6 +235,7 @@
     const FilePath& file_path,
     base::PlatformFileError error_code,
     base::PassPlatformFile file_handle) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   if (base::PLATFORM_FILE_OK != error_code) {
@@ -245,6 +258,7 @@
 
 void URLFetcherCore::FileWriter::DidCloseFile(
     base::PlatformFileError error_code) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
 
   if (base::PLATFORM_FILE_OK != error_code) {
@@ -300,6 +314,7 @@
 }
 
 void URLFetcherCore::Start() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(delegate_task_runner_);
   DCHECK(request_context_getter_) << "We need an URLRequestContext!";
   if (network_task_runner_) {
@@ -315,6 +330,7 @@
 }
 
 void URLFetcherCore::Stop() {
+  TRACK_MEMORY_SCOPE("Network");
   if (delegate_task_runner_)  // May be NULL in tests.
     DCHECK(delegate_task_runner_->BelongsToCurrentThread());
 
@@ -523,6 +539,7 @@
 
 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
                                            FilePath* out_response_path) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
   const bool destination_is_file =
       response_destination_ == URLFetcherCore::TEMP_FILE ||
@@ -543,6 +560,7 @@
 void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
                                         const GURL& new_url,
                                         bool* defer_redirect) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_EQ(request, request_.get());
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (stop_on_redirect_) {
@@ -556,6 +574,7 @@
 }
 
 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK_EQ(request, request_.get());
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (request_->status().is_success()) {
@@ -593,6 +612,7 @@
 
 void URLFetcherCore::OnReadCompleted(URLRequest* request,
                                      int bytes_read) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(request == request_);
   DCHECK(network_task_runner_->BelongsToCurrentThread());
 #if !defined(COBALT)
@@ -714,6 +734,7 @@
 }
 
 void URLFetcherCore::StartURLRequest() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   TRACE_EVENT_ASYNC_STEP0("net::url_request", "URLFetcher", this,
                           "Waiting For Data");
@@ -808,6 +829,7 @@
 }
 
 void URLFetcherCore::StartURLRequestWhenAppropriate() {
+  TRACK_MEMORY_SCOPE("Network");
   TRACE_EVENT_ASYNC_BEGIN1("net::url_request", "URLFetcher", this, "url",
                            original_url_.path());
   DCHECK(network_task_runner_->BelongsToCurrentThread());
@@ -841,6 +863,7 @@
 }
 
 void URLFetcherCore::CancelURLRequest() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
 
   if (request_.get()) {
@@ -862,6 +885,7 @@
 
 void URLFetcherCore::OnCompletedURLRequest(
     base::TimeDelta backoff_delay) {
+  TRACK_MEMORY_SCOPE("Network");
   TRACE_EVENT_ASYNC_END1("net::url_request", "URLFetcher", this, "url",
                          original_url_.path());
   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
@@ -874,12 +898,14 @@
 }
 
 void URLFetcherCore::InformDelegateFetchIsComplete() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
   if (delegate_)
     delegate_->OnURLFetchComplete(fetcher_);
 }
 
 void URLFetcherCore::NotifyMalformedContent() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (url_throttler_entry_ != NULL) {
     int status_code = response_code_;
@@ -896,6 +922,7 @@
 }
 
 void URLFetcherCore::RetryOrCompleteUrlFetch() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   base::TimeDelta backoff_delay;
 
@@ -965,6 +992,7 @@
 }
 
 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
 
   if (original_url_throttler_entry_) {
@@ -986,6 +1014,7 @@
 
 void URLFetcherCore::CompleteAddingUploadDataChunk(
     const std::string& content, bool is_last_chunk) {
+  TRACK_MEMORY_SCOPE("Network");
   if (was_cancelled_) {
     // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
     // may run after the URLFetcher was already stopped.
@@ -1003,6 +1032,7 @@
 // Return false if the write is pending, and the next read will
 // be done later.
 bool URLFetcherCore::WriteBuffer(int num_bytes) {
+  TRACK_MEMORY_SCOPE("Network");
   bool write_complete = false;
   switch (response_destination_) {
     case STRING:
@@ -1031,6 +1061,7 @@
 }
 
 void URLFetcherCore::ReadResponse() {
+  TRACK_MEMORY_SCOPE("Network");
   // Some servers may treat HEAD requests as GET requests.  To free up the
   // network connection as soon as possible, signal that the request has
   // completed immediately, without trying to read any data back (all we care
@@ -1069,6 +1100,7 @@
 #endif  // defined(COBALT)
 
 void URLFetcherCore::InformDelegateUploadProgress() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (request_.get()) {
     int64 current = request_->GetUploadProgress().position();
@@ -1088,12 +1120,14 @@
 
 void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
     int64 current, int64 total) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
   if (delegate_)
     delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
 }
 
 void URLFetcherCore::InformDelegateDownloadDataIfNecessary(int bytes_read) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (delegate_ && delegate_->ShouldSendDownloadData() && bytes_read != 0) {
     if (!download_data_cache_) {
@@ -1114,6 +1148,7 @@
 }
 
 void URLFetcherCore::InformDelegateDownloadData() {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (delegate_ && delegate_->ShouldSendDownloadData() &&
       download_data_cache_) {
@@ -1126,6 +1161,7 @@
 
 void URLFetcherCore::InformDelegateDownloadDataInDelegateThread(
     scoped_ptr<std::string> download_data) {
+  TRACK_MEMORY_SCOPE("Network");
   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
   if (delegate_) {
     delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass());
diff --git a/src/net/url_request/url_request_data_job.cc b/src/net/url_request/url_request_data_job.cc
index 5dffe32..e0c0cba 100644
--- a/src/net/url_request/url_request_data_job.cc
+++ b/src/net/url_request/url_request_data_job.cc
@@ -6,6 +6,7 @@
 
 #include "net/url_request/url_request_data_job.h"
 
+#include "nb/memory_scope.h"
 #include "net/base/data_url.h"
 #include "net/base/net_errors.h"
 
@@ -27,6 +28,7 @@
                                std::string* charset,
                                std::string* data,
                                const CompletionCallback& callback) const {
+  TRACK_MEMORY_SCOPE("Network");
   // Check if data URL is valid. If not, don't bother to try to extract data.
   // Otherwise, parse the data from the data URL.
   const GURL& url = request_->url();
diff --git a/src/starboard/build/convert_i18n_data.py b/src/starboard/build/convert_i18n_data.py
index a34916a..0f56a59 100644
--- a/src/starboard/build/convert_i18n_data.py
+++ b/src/starboard/build/convert_i18n_data.py
@@ -51,7 +51,7 @@
   messages = root[0]
 
   # Write each message to the output file on its own line.
-  with open(output_filename, 'w') as output_file:
+  with open(output_filename, 'wb') as output_file:
     for msg in messages:
       # Use ; as the separator. Which means it better not be in the name.
       assert not (';' in msg.attrib['name'])
diff --git a/src/starboard/client_porting/poem/getenv_stub_poem.h b/src/starboard/client_porting/poem/getenv_stub_poem.h
new file mode 100644
index 0000000..8e4ab81
--- /dev/null
+++ b/src/starboard/client_porting/poem/getenv_stub_poem.h
@@ -0,0 +1,28 @@
+// 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) stub implementation for getenv.
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+
+#include <stdlib.h>
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE const char* getenv(const char* unused) {
+  return NULL;
+}
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
diff --git a/src/starboard/client_porting/poem/inet_poem.h b/src/starboard/client_porting/poem/inet_poem.h
new file mode 100644
index 0000000..55cf47a
--- /dev/null
+++ b/src/starboard/client_porting/poem/inet_poem.h
@@ -0,0 +1,27 @@
+// 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 usually declared in <arpa/inet.h>
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+
+#include "starboard/byte_swap.h"
+
+#define htonl(x) SB_HOST_TO_NET_U32(x)
+#define htons(x) SB_HOST_TO_NET_U16(x)
+#define ntohl(x) SB_NET_TO_HOST_U32(x)
+#define ntohs(x) SB_NET_TO_HOST_U16(x)
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
diff --git a/src/starboard/client_porting/poem/poem.gyp b/src/starboard/client_porting/poem/poem.gyp
index def3f4e..947cc36 100644
--- a/src/starboard/client_porting/poem/poem.gyp
+++ b/src/starboard/client_porting/poem/poem.gyp
@@ -19,10 +19,13 @@
       'type': 'static_library',
       'sources': [
         'eztime_poem.h',
+        'getenv_stub_poem.h',
+        'inet_poem.h',
         'stdio_poem.h',
         'stdlib_poem.h',
         'string_poem.h',
         'strings_poem.h',
+        'strnlen_poem.h',
         'wchar_poem.h',
       ],
       'dependencies': [
@@ -44,5 +47,16 @@
         '<(DEPTH)/starboard/starboard.gyp:starboard',
       ],
     },
+    {
+      'target_name': 'poem_unittests_deploy',
+      'type': 'none',
+      'dependencies': [
+        'poem_unittests',
+      ],
+      'variables': {
+        'executable_name': 'poem_unittests',
+      },
+      'includes': [ '../../build/deploy.gypi' ],
+    },
   ],
 }
diff --git a/src/starboard/client_porting/poem/string_poem_test.cc b/src/starboard/client_porting/poem/string_poem_test.cc
index 2243b48..1a3e899 100644
--- a/src/starboard/client_porting/poem/string_poem_test.cc
+++ b/src/starboard/client_porting/poem/string_poem_test.cc
@@ -17,6 +17,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "starboard/client_porting/poem/string_poem.h"
+#include "starboard/client_porting/poem/strnlen_poem.h"
 
 namespace starboard {
 namespace nplb {
@@ -76,6 +77,20 @@
   EXPECT_STREQ(a, "Wu");
 }
 
+TEST(StringPoemTest, PoemStringGetLengthFixed) {
+  char a[] = "abcdef";
+  char b[] = "abc\0def";
+
+  EXPECT_EQ(strnlen(a, 0), 0);
+  EXPECT_EQ(strnlen(a, 3), 3);
+  EXPECT_EQ(strnlen(a, sizeof(a)), 6);
+  EXPECT_EQ(strnlen(a, 256), 6);
+  EXPECT_EQ(strnlen(b, 2), 2);
+  EXPECT_EQ(strnlen(b, 3), 3);
+  EXPECT_EQ(strnlen(b, sizeof(b)), 3);
+  EXPECT_EQ(strnlen(b, 256), 3);
+}
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/src/starboard/client_porting/poem/strnlen_poem.h b/src/starboard/client_porting/poem/strnlen_poem.h
new file mode 100644
index 0000000..fb2d674
--- /dev/null
+++ b/src/starboard/client_porting/poem/strnlen_poem.h
@@ -0,0 +1,33 @@
+// 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) implementation for strnlen. Usually declared in
+// <string.h>, but may be missing on some platforms (e.g. PS3).
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE size_t StringGetLengthFixed(const char* s, size_t maxlen) {
+  size_t i = 0;
+  while (i < maxlen && s[i]) {
+    ++i;
+  }
+  return i;
+}
+
+#define strnlen(s, maxlen) StringGetLengthFixed(s, maxlen)
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.cc b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
new file mode 100644
index 0000000..732ea14
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
@@ -0,0 +1,281 @@
+// 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/client_porting/pr_starboard/pr_starboard.h"
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/queue.h"
+#include "starboard/thread.h"
+#include "starboard/time.h"
+#include "starboard/types.h"
+
+namespace {
+
+typedef starboard::Queue<bool> SetupSignalQueue;
+
+// Utility function to convert a PRInterval to signed 64 bit integer
+// microseconds.
+int64_t PR_IntervalToMicrosecondsInt64(PRIntervalTime ticks) {
+  uint32_t microseconds_as_uint32 = PR_IntervalToMicroseconds(ticks);
+  int64_t microseconds_as_int64 = static_cast<int64_t>(microseconds_as_uint32);
+  return microseconds_as_int64;
+}
+
+// Struct to bundle up arguments to be passed into SbThreadCreate.
+struct ThreadEntryPointWrapperContext {
+  ThreadEntryPointWrapperContext(void* pr_context,
+                                 PRThread* pr_thread,
+                                 PRThreadEntryPoint pr_entry_point,
+                                 SetupSignalQueue* setup_signal_queue)
+      : pr_context(pr_context),
+        pr_thread(pr_thread),
+        pr_entry_point(pr_entry_point),
+        setup_signal_queue(setup_signal_queue) {}
+  void* pr_context;
+  PRThread* pr_thread;
+  PRThreadEntryPoint pr_entry_point;
+  SetupSignalQueue* setup_signal_queue;
+};
+
+// The thread local key that corresponds to where local PRThread* data is held.
+SbThreadLocalKey g_pr_thread_local_key = kSbThreadLocalKeyInvalid;
+// The SbOnceControlStructure to to ensure that the local key is only created
+// once.
+SbOnceControl g_pr_thread_key_once_control = SB_ONCE_INITIALIZER;
+
+void PrThreadDtor(void* value) {
+  PRThread* pr_thread = reinterpret_cast<PRThread*>(value);
+  delete pr_thread;
+}
+
+void InitPrThreadKey() {
+  g_pr_thread_local_key = SbThreadCreateLocalKey(PrThreadDtor);
+}
+
+SbThreadLocalKey GetPrThreadKey() {
+  SB_CHECK(SbOnce(&g_pr_thread_key_once_control, InitPrThreadKey));
+  return g_pr_thread_local_key;
+}
+
+void* ThreadEntryPointWrapper(void* context_as_void_pointer) {
+  ThreadEntryPointWrapperContext* context =
+      reinterpret_cast<ThreadEntryPointWrapperContext*>(
+          context_as_void_pointer);
+  void* pr_context = context->pr_context;
+  PRThreadEntryPoint pr_entry_point = context->pr_entry_point;
+  PRThread* pr_thread = context->pr_thread;
+  SetupSignalQueue* setup_signal_queue = context->setup_signal_queue;
+
+  delete context;
+
+  pr_thread->sb_thread = SbThreadGetCurrent();
+  SbThreadLocalKey key = GetPrThreadKey();
+  SB_CHECK(SbThreadIsValidLocalKey(key));
+  SbThreadSetLocalValue(key, pr_thread);
+
+  setup_signal_queue->Put(true);
+  pr_entry_point(pr_context);
+
+  return NULL;
+}
+
+}  // namespace
+
+PRLock* PR_NewLock() {
+  PRLock* lock = new PRLock();
+  if (!SbMutexCreate(lock)) {
+    delete lock;
+    return NULL;
+  }
+  return lock;
+}
+
+void PR_DestroyLock(PRLock* lock) {
+  SB_DCHECK(lock);
+  SbMutexDestroy(lock);
+  delete lock;
+}
+
+PRCondVar* PR_NewCondVar(PRLock* lock) {
+  SB_DCHECK(lock);
+  PRCondVar* cvar = new PRCondVar();
+  if (!SbConditionVariableCreate(&cvar->sb_condition_variable, lock)) {
+    delete cvar;
+    return NULL;
+  }
+  cvar->lock = lock;
+  return cvar;
+}
+
+void PR_DestroyCondVar(PRCondVar* cvar) {
+  SbConditionVariableDestroy(&cvar->sb_condition_variable);
+  delete cvar;
+}
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout) {
+  SbConditionVariableResult result;
+  if (timeout == PR_INTERVAL_NO_WAIT) {
+    result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+                                          cvar->lock, 0);
+  } else if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+    result = SbConditionVariableWait(&cvar->sb_condition_variable, cvar->lock);
+  } else {
+    int64_t microseconds = PR_IntervalToMicrosecondsInt64(timeout);
+    result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+                                          cvar->lock, microseconds);
+  }
+  return pr_starboard::ToPRStatus(result != kSbConditionVariableFailed);
+}
+
+PRThread* PR_GetCurrentThread() {
+  SbThreadLocalKey key = GetPrThreadKey();
+  SB_CHECK(SbThreadIsValidLocalKey(key));
+
+  PRThread* value = static_cast<PRThread*>(SbThreadGetLocalValue(key));
+  // We could potentially be a thread that was not created through
+  // PR_CreateThread.  In this case, we must allocate a PRThread and do the
+  // setup that would normally have been done in PR_CreateThread.
+  if (!value) {
+    PRThread* pr_thread = new PRThread(SbThreadGetCurrent());
+    SbThreadSetLocalValue(key, pr_thread);
+    value = pr_thread;
+  }
+
+  return value;
+}
+
+uint32_t PR_snprintf(char* out, uint32_t outlen, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  uint32_t ret = PR_vsnprintf(out, outlen, fmt, args);
+  va_end(args);
+  return ret;
+}
+
+PRThread* PR_CreateThread(PRThreadType type,
+                          PRThreadEntryPoint start,
+                          void* arg,
+                          PRThreadPriority priority,
+                          PRThreadScope scope,
+                          PRThreadState state,
+                          PRUint32 stackSize) {
+  int64_t sb_stack_size = static_cast<int64_t>(stackSize);
+
+  SbThreadPriority sb_priority;
+  switch (priority) {
+    case PR_PRIORITY_LOW:
+      sb_priority = kSbThreadPriorityLow;
+      break;
+    case PR_PRIORITY_NORMAL:
+      sb_priority = kSbThreadPriorityNormal;
+      break;
+    case PR_PRIORITY_HIGH:
+      sb_priority = kSbThreadPriorityHigh;
+      break;
+    case PR_PRIORITY_LAST:
+      sb_priority = kSbThreadPriorityHighest;
+      break;
+    default:
+      sb_priority = kSbThreadNoPriority;
+  }
+
+  SbThreadAffinity sb_affinity = kSbThreadNoAffinity;
+
+  SB_DCHECK(state == PR_JOINABLE_THREAD || state == PR_UNJOINABLE_THREAD);
+  bool sb_joinable = (state == PR_JOINABLE_THREAD);
+
+  // This heap allocated PRThread object will have a pointer to it stored in
+  // the newly created child thread's thread local storage.  Once the newly
+  // created child thread finishes, it will be freed in the destructor
+  // associated with it through thread local storage.
+  PRThread* pr_thread = new PRThread(kSbThreadInvalid);
+
+  // Utility queue for the ThreadEntryWrapper to signal us once it's done
+  // running its initial setup and we can safely exit.
+  SetupSignalQueue setup_signal_queue;
+
+  // This heap allocated context object is freed after
+  // ThreadEntryPointWrapper's initial setup is complete, right before the
+  // nspr level entry point is run.
+  ThreadEntryPointWrapperContext* context = new ThreadEntryPointWrapperContext(
+      arg, pr_thread, start, &setup_signal_queue);
+
+  // Note that pr_thread->sb_thread will be set to the correct value in the
+  // setup section of ThreadEntryPointWrapper.  It is done there rather than
+  // here to account for the unlikely but possible case in which we enter the
+  // newly created child thread, and then the child thread passes references
+  // to itself off into its potential children or co-threads that interact
+  // with it before we can copy what SbThreadCreate returns into
+  // pr_thread->sb_thread from this current thread.
+  SbThreadCreate(sb_stack_size, sb_priority, sb_affinity, sb_joinable, NULL,
+                 ThreadEntryPointWrapper, context);
+
+  // Now we must wait for the setup section of ThreadEntryPointWrapper to run
+  // and initialize pr_thread (both the struct itself and the corresponding
+  // new thread's private data) before we can safely return.  We expect to
+  // receive true rather than false by convention.
+  bool setup_signal = setup_signal_queue.Get();
+  SB_DCHECK(setup_signal);
+
+  return pr_thread;
+}
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+                            PRCallOnceWithArgFN func,
+                            void* arg) {
+  SB_NOTREACHED() << "Not implemented";
+  return PR_FAILURE;
+}
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+                                  PRThreadPrivateDTOR destructor) {
+  SbThreadLocalKey key = SbThreadCreateLocalKey(destructor);
+  if (!SbThreadIsValidLocalKey(key)) {
+    return pr_starboard::ToPRStatus(false);
+  }
+  *newIndex = key;
+  return pr_starboard::ToPRStatus(true);
+}
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli) {
+  PRUint64 tock = static_cast<PRUint64>(milli);
+  PRUint64 msecPerSec = static_cast<PRInt64>(PR_MSEC_PER_SEC);
+  PRUint64 rounding = static_cast<PRInt64>(PR_MSEC_PER_SEC >> 1);
+  PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+
+  tock *= tps;
+  tock += rounding;
+  tock /= msecPerSec;
+
+  PRUint64 ticks = static_cast<PRUint64>(tock);
+  return ticks;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks) {
+  PRUint64 tock = static_cast<PRInt64>(ticks);
+  PRUint64 usecPerSec = static_cast<PRInt64>(PR_USEC_PER_SEC);
+  PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+  PRUint64 rounding = static_cast<PRUint64>(tps) >> 1;
+
+  tock *= usecPerSec;
+  tock += rounding;
+  tock /= tps;
+
+  PRUint32 micro = static_cast<PRUint32>(tock);
+  return micro;
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.gyp b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
new file mode 100644
index 0000000..0874b65
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'pr_starboard',
+      'type': 'static_library',
+      'sources': [
+        'pr_starboard.cc',
+        'pr_starboard.h',
+      ],
+      'dependencies': [
+        '<(DEPTH)/starboard/starboard.gyp:starboard',
+      ],
+    },
+  ],
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.h b/src/starboard/client_porting/pr_starboard/pr_starboard.h
new file mode 100644
index 0000000..63e5c4d
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.h
@@ -0,0 +1,189 @@
+// 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.
+
+// This header defines the interface for a starboard based implementation of
+// the subset of nspr that SpiderMonkey depends on.  It directly matches the
+// NSPR API, with the exception that accessing thread local data should use
+// PRTLSIndex, rather than PRUintn.
+
+#ifndef STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+#define STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/string.h"
+#include "starboard/thread.h"
+#include "starboard/types.h"
+
+#define PR_CALLBACK
+
+#define PR_MSEC_PER_SEC 1000L
+#define PR_USEC_PER_SEC 1000000L
+#define PR_NSEC_PER_SEC 1000000000L
+#define PR_USEC_PER_MSEC 1000L
+#define PR_NSEC_PER_MSEC 1000000L
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+namespace pr_starboard {
+
+// Utility function to map true to PR_SUCCESS and false to PR_FAILURE.
+static inline PRStatus ToPRStatus(bool result) {
+  return result ? PR_SUCCESS : PR_FAILURE;
+}
+
+}  // namespace pr_starboard
+
+typedef enum PRThreadPriority {
+  PR_PRIORITY_FIRST = 0,
+  PR_PRIORITY_LOW = 0,
+  PR_PRIORITY_NORMAL = 1,
+  PR_PRIORITY_HIGH = 2,
+  PR_PRIORITY_URGENT = 3,
+  PR_PRIORITY_LAST = 3
+} PRThreadPriority;
+
+typedef enum PRThreadScope {
+  PR_LOCAL_THREAD,
+  PR_GLOBAL_THREAD,
+  PR_GLOBAL_BOUND_THREAD
+} PRThreadScope;
+
+typedef enum PRThreadState {
+  PR_JOINABLE_THREAD,
+  PR_UNJOINABLE_THREAD
+} PRThreadState;
+
+typedef enum PRThreadType { PR_USER_THREAD, PR_SYSTEM_THREAD } PRThreadType;
+
+typedef SbThreadLocalKey PRTLSIndex;
+typedef uint32_t PRIntervalTime;
+
+typedef int32_t PRInt32;
+typedef uint32_t PRUint32;
+
+typedef int64_t PRInt64;
+typedef uint64_t PRUint64;
+
+typedef void(PR_CALLBACK* PRThreadPrivateDTOR)(void* priv);
+
+struct PRThread {
+  explicit PRThread(SbThread sb_thread) : sb_thread(sb_thread) {}
+  SbThread sb_thread;
+};
+
+typedef SbMutex PRLock;
+
+#define PR_INTERVAL_NO_WAIT 0UL
+#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL
+
+struct PRCondVar {
+  SbConditionVariable sb_condition_variable;
+  SbMutex* lock;
+};
+
+PRLock* PR_NewLock();
+
+static inline void PR_Lock(PRLock* lock) {
+  SbMutexAcquire(lock);
+}
+
+static inline void PR_Unlock(PRLock* lock) {
+  SbMutexRelease(lock);
+}
+
+void PR_DestroyLock(PRLock* lock);
+
+PRCondVar* PR_NewCondVar(PRLock* lock);
+
+void PR_DestroyCondVar(PRCondVar* cvar);
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout);
+
+static inline PRStatus PR_NotifyCondVar(PRCondVar* cvar) {
+  return pr_starboard::ToPRStatus(
+      SbConditionVariableSignal(&cvar->sb_condition_variable));
+}
+
+static inline PRStatus PR_NotifyAllCondVar(PRCondVar* cvar) {
+  return pr_starboard::ToPRStatus(
+      SbConditionVariableBroadcast(&cvar->sb_condition_variable));
+}
+
+typedef void (*PRThreadEntryPoint)(void*);
+
+PRThread* PR_CreateThread(PRThreadType type,
+                          PRThreadEntryPoint start,
+                          void* arg,
+                          PRThreadPriority priority,
+                          PRThreadScope scope,
+                          PRThreadState state,
+                          PRUint32 stackSize);
+
+static inline PRStatus PR_JoinThread(PRThread* pr_thread) {
+  SB_DCHECK(pr_thread);
+  SB_DCHECK(SbThreadIsValid(pr_thread->sb_thread));
+  return pr_starboard::ToPRStatus(SbThreadJoin(pr_thread->sb_thread, NULL));
+}
+
+PRThread* PR_GetCurrentThread();
+
+void PR_DetachThread();
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+                                  PRThreadPrivateDTOR destructor);
+
+static inline PRStatus PR_SetThreadPrivate(PRTLSIndex index, void* priv) {
+  return pr_starboard::ToPRStatus(SbThreadSetLocalValue(index, priv));
+}
+
+static inline void* PR_GetThreadPrivate(PRTLSIndex index) {
+  return SbThreadGetLocalValue(index);
+}
+
+static inline void PR_SetCurrentThreadName(const char* name) {
+  SbThreadSetName(name);
+}
+
+static inline PRUint32 PR_vsnprintf(char* out,
+                                    PRUint32 outlen,
+                                    const char* fmt,
+                                    va_list ap) {
+  return static_cast<PRUint32>(SbStringFormat(out, outlen, fmt, ap));
+}
+
+PRUint32 PR_snprintf(char* out, PRUint32 outlen, const char* fmt, ...);
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli);
+
+static inline PRIntervalTime PR_MicrosecondsToInterval(PRUint32 micro) {
+  return (micro + 999) / 1000;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks);
+
+struct PRCallOnceType {};
+typedef PRStatus(PR_CALLBACK* PRCallOnceWithArgFN)(void* arg);
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+                            PRCallOnceWithArgFN func,
+                            void* arg);
+
+static inline PRUint32 PR_TicksPerSecond() {
+  return 1000;
+}
+
+#endif  // STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
diff --git a/src/starboard/client_porting/wrap_main/wrap_main.h b/src/starboard/client_porting/wrap_main/wrap_main.h
index e4879d3..4734772 100644
--- a/src/starboard/client_porting/wrap_main/wrap_main.h
+++ b/src/starboard/client_porting/wrap_main/wrap_main.h
@@ -50,6 +50,11 @@
 }  // namespace client_porting
 }  // namespace starboard
 
+#if defined(_WIN32)
+// Today there is no Starboard win32. Make sure those who create it know
+// the _CrtSet* functions below should be moved to starboard win32 main.
+#error For starboard win32, please move _CrtSet* to main
+#endif
 #define STARBOARD_WRAP_SIMPLE_MAIN(main_function)                \
   void SbEventHandle(const SbEvent* event) {                     \
     ::starboard::client_porting::wrap_main::SimpleEventHandler<  \
@@ -57,10 +62,26 @@
   }
 
 #else
+#if defined(_WIN32)
+#include <windows.h>
+
+// TODO this case should be removed when win32 is starboardized
+#define STARBOARD_WRAP_SIMPLE_MAIN(main_function)                             \
+  int main(int argc, char** argv) {                                           \
+    if (!IsDebuggerPresent()) {                                               \
+      _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); \
+      _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);  \
+      _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);   \
+      _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);                    \
+    }                                                                         \
+    return main_function(argc, argv);                                         \
+  }
+#else  // defined(_WIN32)
 #define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
   int main(int argc, char** argv) {               \
     return main_function(argc, argv);             \
   }
+#endif
 
 #endif  // STARBOARD
 #endif  // STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
diff --git a/src/starboard/condition_variable.h b/src/starboard/condition_variable.h
index 673b7d9..4c519ba 100644
--- a/src/starboard/condition_variable.h
+++ b/src/starboard/condition_variable.h
@@ -56,10 +56,6 @@
 // placing the newly created condition variable in |out_condition|.
 //
 // The return value indicates whether the condition variable could be created.
-//
-// TODO: It looks like WTF does not have the mutex available when creating
-// the condition variable, and pthreads doesn't appear to require the mutex on
-// condvar creation, so we should just remove the parameter.
 SB_EXPORT bool SbConditionVariableCreate(SbConditionVariable* out_condition,
                                          SbMutex* opt_mutex);
 
diff --git a/src/starboard/examples/window/main.cc b/src/starboard/examples/window/main.cc
index 381d428..bb5bc83 100644
--- a/src/starboard/examples/window/main.cc
+++ b/src/starboard/examples/window/main.cc
@@ -35,7 +35,7 @@
                     << ", window=" << data->window
                     << ", device_type=" << data->device_type
                     << ", device_id=" << data->device_id
-                    << ", key=" << data->key
+                    << ", key=0x" << std::hex << data->key
                     << ", character=" << data->character
                     << ", modifiers=0x" << std::hex << data->key_modifiers
                     << ", location=" << std::dec << data->key_location;
diff --git a/src/starboard/linux/x64directfb/sanitizer_options.cc b/src/starboard/linux/x64directfb/sanitizer_options.cc
new file mode 100644
index 0000000..e85d451
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sanitizer_options.cc
@@ -0,0 +1,42 @@
+// 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.
+
+// Removes gallium leak warnings from x11 GL code, but defines it as a weak
+// symbol, so other code can override it if they want to.
+
+#if defined(ADDRESS_SANITIZER)
+
+// Functions returning default options are declared weak in the tools' runtime
+// libraries. To make the linker pick the strong replacements for those
+// functions from this module, we explicitly force its inclusion by passing
+// -Wl,-u_sanitizer_options_link_helper
+extern "C" void _sanitizer_options_link_helper() { }
+
+#define SANITIZER_HOOK_ATTRIBUTE          \
+  extern "C"                              \
+  __attribute__((no_sanitize_address))    \
+  __attribute__((no_sanitize_memory))     \
+  __attribute__((no_sanitize_thread))     \
+  __attribute__((visibility("default")))  \
+  __attribute__((weak))                   \
+  __attribute__((used))
+
+// Newline separated list of issues to suppress, see
+// http://clang.llvm.org/docs/AddressSanitizer.html#issue-suppression
+// http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc
+SANITIZER_HOOK_ATTRIBUTE const char* __lsan_default_suppressions() {
+  return "leak:*eglibc-2.19*\n";
+}
+
+#endif  // defined(ADDRESS_SANITIZER)
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gypi b/src/starboard/linux/x64directfb/starboard_platform.gypi
index f5d40ad..d38e23c 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gypi
+++ b/src/starboard/linux/x64directfb/starboard_platform.gypi
@@ -17,6 +17,7 @@
   'variables': {
     'starboard_platform_sources': [
         '<(DEPTH)/starboard/linux/x64directfb/main.cc',
+        '<(DEPTH)/starboard/linux/x64directfb/sanitizer_options.cc',
         '<(DEPTH)/starboard/linux/x64directfb/system_get_property.cc',
         '<(DEPTH)/starboard/shared/directfb/application_directfb.cc',
         '<(DEPTH)/starboard/shared/directfb/blitter_blit_rect_to_rect.cc',
diff --git a/src/starboard/nplb/decode_target_create_test.cc b/src/starboard/nplb/decode_target_create_test.cc
index e8f3ea4..287dc21 100644
--- a/src/starboard/nplb/decode_target_create_test.cc
+++ b/src/starboard/nplb/decode_target_create_test.cc
@@ -44,7 +44,6 @@
 
   SbDecodeTarget target =
       SbDecodeTargetCreate(kSbDecodeTargetFormat1PlaneRGBA, &surface);
-  EXPECT_TRUE(SbDecodeTargetIsValid(target));
   if (SbDecodeTargetIsValid(target)) {
     SbBlitterSurface plane =
         SbDecodeTargetGetPlane(target, kSbDecodeTargetPlaneRGBA);
diff --git a/src/starboard/nplb/storage_helpers.h b/src/starboard/nplb/storage_helpers.h
index 56b4fc2..efc422e 100644
--- a/src/starboard/nplb/storage_helpers.h
+++ b/src/starboard/nplb/storage_helpers.h
@@ -27,12 +27,12 @@
 const int64_t kStorageSize2 = kStorageSize * 2 + kStorageOffset;
 
 // Deletes the storage for the current user.
-SB_C_INLINE void ClearStorageRecord() {
+static SB_C_INLINE void ClearStorageRecord() {
   SbStorageDeleteRecord(SbUserGetCurrent());
 }
 
 // Opens the storage record for the current user, validating that it is valid.
-SB_C_INLINE SbStorageRecord OpenStorageRecord() {
+static SB_C_INLINE SbStorageRecord OpenStorageRecord() {
   SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent());
   EXPECT_TRUE(SbStorageIsValidRecord(record));
   return record;
@@ -40,7 +40,8 @@
 
 // Writes a standard pattern of |size| bytes into the given open storage
 // |record|.
-SB_C_INLINE void WriteStorageRecord(SbStorageRecord record, int64_t size) {
+static SB_C_INLINE void WriteStorageRecord(SbStorageRecord record,
+                                           int64_t size) {
   char* data = new char[size];
   for (int64_t i = 0; i < size; ++i) {
     data[i] = static_cast<char>(i + 2 % 0xFF);
@@ -52,7 +53,8 @@
 
 // Ensures that the storage record for the current user is initialized with the
 // standard pattern for exactly |length| bytes.
-SB_C_INLINE void InitializeStorageRecord(int64_t length) {
+
+static SB_C_INLINE void InitializeStorageRecord(int64_t length) {
   ClearStorageRecord();
   SbStorageRecord record = OpenStorageRecord();
   WriteStorageRecord(record, length);
@@ -62,7 +64,7 @@
 // Checks a buffer of |total| size for the expected pattern (written in
 // WriteStorageRecord) to start at |offset| and continue for |length|, and the
 // rest of the buffer, before and after, should be set to 0.
-SB_C_INLINE void CheckStorageBuffer(char* data,
+static SB_C_INLINE void CheckStorageBuffer(char* data,
                                     int64_t offset,
                                     int64_t length,
                                     int64_t total) {
@@ -83,7 +85,7 @@
 // |offset| and reporting the buffer size as |length|, checks that the number of
 // read bytes is |expected_length| and then checks the buffer for the expected
 // pattern written in WriteStorageRecord over the expected range of the buffer.
-SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
+static SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
                                      int64_t offset,
                                      int64_t expected_length,
                                      int64_t length,
diff --git a/src/starboard/player.h b/src/starboard/player.h
index 6fbc381..cbd1ff3 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -173,7 +173,7 @@
 #define kSbPlayerInvalid ((SbPlayer)NULL)
 
 // Returns whether the given player handle is valid.
-SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
+static SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
   return player != kSbPlayerInvalid;
 }
 
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi
index fbccc08..040ca1e 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -32,7 +32,8 @@
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
     'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
+    'cobalt_enable_jit': 0,
+    'cobalt_minimum_frame_time_in_milliseconds': '33',
 
     # RasPi 1 is ARMv6
     'arm_version': 6,
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index fb203a6..c39d4e3 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -39,6 +39,8 @@
         '<(DEPTH)/starboard/raspi/shared/main.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.h',
+        '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.cc',
+        '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.h',
         '<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.h',
         '<(DEPTH)/starboard/raspi/shared/thread_create_priority.cc',
diff --git a/src/starboard/raspi/shared/application_dispmanx.cc b/src/starboard/raspi/shared/application_dispmanx.cc
index fcaf43f..4f9dddf 100644
--- a/src/starboard/raspi/shared/application_dispmanx.cc
+++ b/src/starboard/raspi/shared/application_dispmanx.cc
@@ -51,9 +51,7 @@
   window_ = new SbWindowPrivate(*display_, options);
   input_ = DevInput::Create(window_);
 
-  // Create the dispmanx element to display video frames.
-  int result = 0;
-  uint32_t vc_image_ptr;
+  video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
 
   return window_;
 }
@@ -86,14 +84,11 @@
 }
 
 void ApplicationDispmanx::AcceptFrame(SbPlayer player,
-                                      const VideoFrame& frame,
+                                      const scoped_refptr<VideoFrame>& frame,
                                       int x,
                                       int y,
                                       int width,
                                       int height) {
-  if (!video_renderer_) {
-    video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
-  }
   video_renderer_->Update(frame);
 }
 
diff --git a/src/starboard/raspi/shared/application_dispmanx.h b/src/starboard/raspi/shared/application_dispmanx.h
index ba49ff5..d08c406 100644
--- a/src/starboard/raspi/shared/application_dispmanx.h
+++ b/src/starboard/raspi/shared/application_dispmanx.h
@@ -49,7 +49,7 @@
   void Initialize() SB_OVERRIDE;
   void Teardown() SB_OVERRIDE;
   void AcceptFrame(SbPlayer player,
-                   const VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
diff --git a/src/starboard/raspi/shared/dispmanx_util.cc b/src/starboard/raspi/shared/dispmanx_util.cc
index 88c7f52..f33a441 100644
--- a/src/starboard/raspi/shared/dispmanx_util.cc
+++ b/src/starboard/raspi/shared/dispmanx_util.cc
@@ -23,6 +23,8 @@
 
 namespace {
 
+const int kElementChangeAttributesFlagSrcRect = 1 << 3;
+
 class DispmanxAutoUpdate {
  public:
   DispmanxAutoUpdate() {
@@ -52,10 +54,61 @@
 
 }  // namespace
 
+DispmanxResource::DispmanxResource(VC_IMAGE_TYPE_T image_type,
+                                   uint32_t width,
+                                   uint32_t height,
+                                   uint32_t visible_width,
+                                   uint32_t visible_height)
+    : width_(width),
+      height_(height),
+      visible_width_(visible_width),
+      visible_height_(visible_height) {
+  static const uint32_t kMaxDimension = 1 << 16;
+
+  SB_DCHECK(width_ > 0 && width_ < kMaxDimension);
+  SB_DCHECK(height_ > 0 && height_ < kMaxDimension);
+  SB_DCHECK(visible_width_ > 0 && visible_width_ < kMaxDimension);
+  SB_DCHECK(visible_height > 0 && visible_height < kMaxDimension);
+  SB_DCHECK(width_ >= visible_width_);
+  SB_DCHECK(height_ >= visible_height);
+
+  uint32_t vc_image_ptr;
+
+  handle_ = vc_dispmanx_resource_create(
+      image_type, visible_width_ | (width_ << 16),
+      visible_height | (height_ << 16), &vc_image_ptr);
+  SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
+}
+
+void DispmanxYUV420Resource::WriteData(const void* data) {
+  SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+  DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
+  int32_t result = vc_dispmanx_resource_write_data(
+      handle(), VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
+  SB_DCHECK(result == 0);
+}
+
 void DispmanxYUV420Resource::ClearWithBlack() {
-  scoped_array<uint8_t> data(new uint8_t[width_ * height_ * 3 / 2]);
-  SbMemorySet(data.get(), width_ * height_, 0);
-  SbMemorySet(data.get() + width_ * height_, width_ * height_ / 2, 0x80);
+  scoped_array<uint8_t> data(new uint8_t[width() * height() * 3 / 2]);
+  SbMemorySet(data.get(), width() * height(), 0);
+  SbMemorySet(data.get() + width() * height(), width() * height() / 2, 0x80);
+  WriteData(data.get());
+}
+
+void DispmanxRGB565Resource::WriteData(const void* data) {
+  SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+  DispmanxRect dst_rect(0, 0, width(), height());
+  int32_t result =
+      vc_dispmanx_resource_write_data(handle(), VC_IMAGE_RGB565, width() * 2,
+                                      const_cast<void*>(data), &dst_rect);
+  SB_DCHECK(result == 0);
+}
+
+void DispmanxRGB565Resource::ClearWithBlack() {
+  scoped_array<uint8_t> data(new uint8_t[width() * height() * 2]);
+  SbMemorySet(data.get(), width() * height() * 2, 0);
   WriteData(data.get());
 }
 
@@ -78,26 +131,37 @@
   SB_DCHECK(result == 0) << " result=" << result;
 }
 
-void DispmanxVideoRenderer::Update(const VideoFrame& video_frame) {
-  if (video_frame.IsEndOfStream()) {
-    element_.reset();
-    resource_.reset();
+void DispmanxElement::ChangeSource(const DispmanxResource& new_src) {
+  DispmanxAutoUpdate update;
+  vc_dispmanx_element_change_source(update.handle(), handle_, new_src.handle());
+}
+
+DispmanxVideoRenderer::DispmanxVideoRenderer(const DispmanxDisplay& display,
+                                             int32_t layer)
+    : black_frame_(256, 256, 256, 256) {
+  black_frame_.ClearWithBlack();
+  element_.reset(new DispmanxElement(display, layer, DispmanxRect(),
+                                     black_frame_, DispmanxRect()));
+}
+
+void DispmanxVideoRenderer::Update(
+    const scoped_refptr<VideoFrame>& video_frame) {
+  SB_DCHECK(video_frame);
+
+  if (frame_ == video_frame) {
     return;
   }
-  if (!resource_ || resource_->width() != video_frame.width() ||
-      resource_->height() != video_frame.height()) {
-    element_.reset();
-    resource_.reset();
 
-    DispmanxRect src_rect(0, 0, video_frame.width() << 16,
-                          video_frame.height() << 16);
-    resource_.reset(
-        new DispmanxYUV420Resource(video_frame.width(), video_frame.height()));
-    element_.reset(new DispmanxElement(display_, layer_, DispmanxRect(),
-                                       *resource_, src_rect));
+  if (video_frame->IsEndOfStream()) {
+    element_->ChangeSource(black_frame_);
+    frame_ = video_frame;
+    return;
   }
 
-  resource_->WriteData(video_frame.GetPlane(0).data);
+  DispmanxYUV420Resource* resource =
+      reinterpret_cast<DispmanxYUV420Resource*>(video_frame->native_texture());
+  element_->ChangeSource(*resource);
+  frame_ = video_frame;
 }
 
 }  // namespace shared
diff --git a/src/starboard/raspi/shared/dispmanx_util.h b/src/starboard/raspi/shared/dispmanx_util.h
index c4b65f6..f051e86 100644
--- a/src/starboard/raspi/shared/dispmanx_util.h
+++ b/src/starboard/raspi/shared/dispmanx_util.h
@@ -69,38 +69,57 @@
   }
 
   DISPMANX_RESOURCE_HANDLE_T handle() const { return handle_; }
+  uint32_t visible_width() const { return visible_width_; }
+  uint32_t visible_height() const { return visible_height_; }
   uint32_t width() const { return width_; }
   uint32_t height() const { return height_; }
 
  protected:
-  DispmanxResource(VC_IMAGE_TYPE_T image_type, uint32_t width, uint32_t height)
-      : width_(width), height_(height) {
-    uint32_t vc_image_ptr;
+  DispmanxResource(VC_IMAGE_TYPE_T image_type,
+                   uint32_t width,
+                   uint32_t height,
+                   uint32_t visible_width,
+                   uint32_t visible_height);
 
-    handle_ =
-        vc_dispmanx_resource_create(image_type, width, height, &vc_image_ptr);
-    SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
-  }
-
+ private:
   DISPMANX_RESOURCE_HANDLE_T handle_;
   uint32_t width_;
   uint32_t height_;
+  uint32_t visible_width_;
+  uint32_t visible_height_;
 
   SB_DISALLOW_COPY_AND_ASSIGN(DispmanxResource);
 };
 
 class DispmanxYUV420Resource : public DispmanxResource {
  public:
-  DispmanxYUV420Resource(uint32_t width, uint32_t height)
-      : DispmanxResource(VC_IMAGE_YUV420, width, height) {}
+  DispmanxYUV420Resource(uint32_t width,
+                         uint32_t height,
+                         uint32_t visible_width,
+                         uint32_t visible_height)
+      : DispmanxResource(VC_IMAGE_YUV420,
+                         width,
+                         height,
+                         visible_width,
+                         visible_height) {}
 
-  void WriteData(const void* data) {
-    SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
-    DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
-    int32_t result = vc_dispmanx_resource_write_data(
-        handle_, VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
-    SB_DCHECK(result == 0);
-  }
+  void WriteData(const void* data);
+  void ClearWithBlack();
+};
+
+class DispmanxRGB565Resource : public DispmanxResource {
+ public:
+  DispmanxRGB565Resource(uint32_t width,
+                         uint32_t height,
+                         uint32_t visible_width,
+                         uint32_t visible_height)
+      : DispmanxResource(VC_IMAGE_RGB565,
+                         width,
+                         height,
+                         visible_width,
+                         visible_height) {}
+
+  void WriteData(const void* data);
   void ClearWithBlack();
 };
 
@@ -114,6 +133,7 @@
   ~DispmanxElement();
 
   DISPMANX_ELEMENT_HANDLE_T handle() const { return handle_; }
+  void ChangeSource(const DispmanxResource& new_src);
 
  private:
   DISPMANX_ELEMENT_HANDLE_T handle_;
@@ -124,16 +144,18 @@
 class DispmanxVideoRenderer {
  public:
   typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
-  DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer)
-      : display_(display), layer_(layer) {}
 
-  void Update(const VideoFrame& video_frame);
+  DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer);
+
+  void Update(const scoped_refptr<VideoFrame>& video_frame);
 
  private:
-  const DispmanxDisplay& display_;
-  int32_t layer_;
-  scoped_ptr<DispmanxYUV420Resource> resource_;
   scoped_ptr<DispmanxElement> element_;
+  scoped_refptr<VideoFrame> frame_;
+
+  // Used to fill the background with black if no video is playing so that the
+  // console does not show through.
+  DispmanxRGB565Resource black_frame_;
 
   SB_DISALLOW_COPY_AND_ASSIGN(DispmanxVideoRenderer);
 };
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.cc b/src/starboard/raspi/shared/open_max/open_max_component.cc
index eb05825..bb814f6c 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.cc
+++ b/src/starboard/raspi/shared/open_max/open_max_component.cc
@@ -47,15 +47,13 @@
 
 }  // namespace
 
-OpenMaxComponent::OpenMaxComponent(const char* name, size_t minimum_output_size)
+OpenMaxComponent::OpenMaxComponent(const char* name)
     : condition_variable_(mutex_),
-      minimum_output_size_(minimum_output_size),
       handle_(NULL),
       input_port_(kInvalidPort),
       output_port_(kInvalidPort),
       output_setting_changed_(false),
-      output_buffer_(NULL),
-      output_buffer_filled_(false) {
+      output_port_enabled_(false) {
   InitializeOpenMax();
 
   OMX_CALLBACKTYPE callbacks;
@@ -99,18 +97,20 @@
   SendCommandAndWaitForCompletion(OMX_CommandFlush, output_port_);
 
   SendCommand(OMX_CommandPortDisable, input_port_);
-  for (BufferHeaders::iterator iter = unused_buffers_.begin();
-       iter != unused_buffers_.end(); ++iter) {
-    OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, input_port_, *iter);
+  for (size_t i = 0; i < input_buffers_.size(); ++i) {
+    OMX_ERRORTYPE error =
+        OMX_FreeBuffer(handle_, input_port_, input_buffers_[i]);
     SB_DCHECK(error == OMX_ErrorNone);
   }
   WaitForCommandCompletion();
 
   SendCommand(OMX_CommandPortDisable, output_port_);
-  if (output_buffer_) {
-    OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, output_port_, output_buffer_);
+  for (size_t i = 0; i < output_buffers_.size(); ++i) {
+    OMX_ERRORTYPE error =
+        OMX_FreeBuffer(handle_, output_port_, output_buffers_[i]);
     SB_DCHECK(error == OMX_ErrorNone);
   }
+  output_buffers_.clear();
   WaitForCommandCompletion();
 
   SendCommandAndWaitForCompletion(OMX_CommandStateSet, OMX_StateLoaded);
@@ -162,45 +162,34 @@
   SB_DCHECK(error == OMX_ErrorNone);
 }
 
-bool OpenMaxComponent::ReadVideoFrame(VideoFrame* frame) {
+OMX_BUFFERHEADERTYPE* OpenMaxComponent::PeekNextOutputBuffer() {
   {
     ScopedLock scoped_lock(mutex_);
-    if (output_buffer_ && !output_buffer_filled_) {
-      return false;
-    }
+
     if (!output_setting_changed_) {
-      return false;
+      return NULL;
     }
   }
-  SB_DCHECK(output_setting_changed_);
-  if (!output_buffer_) {
-    GetOutputPortParam(&output_port_definition_);
-    SB_DCHECK(output_port_definition_.format.video.eColorFormat ==
-              OMX_COLOR_FormatYUV420PackedPlanar);
-    EnableOutputPortAndAllocateBuffer();
-    return false;
-  }
 
-  if (output_buffer_->nFlags & OMX_BUFFERFLAG_EOS) {
-    *frame = VideoFrame();
-    return true;
+  if (!output_port_enabled_) {
+    EnableOutputPortAndAllocateBuffer();
   }
-  SbMediaTime timestamp =
-      ((output_buffer_->nTimeStamp.nHighPart * 0x100000000ull) +
-       output_buffer_->nTimeStamp.nLowPart) *
-      kSbMediaTimeSecond / kSbTimeSecond;
-  int width = output_port_definition_.format.video.nFrameWidth;
-  int height = output_port_definition_.format.video.nSliceHeight;
-  int pitch = output_port_definition_.format.video.nStride;
-  *frame = VideoFrame::CreateYV12Frame(
-      width, height, pitch, timestamp, output_buffer_->pBuffer,
-      output_buffer_->pBuffer + pitch * height,
-      output_buffer_->pBuffer + pitch * height * 5 / 4);
-  output_buffer_filled_ = false;
-  output_buffer_->nFilledLen = 0;
-  OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffer_);
+
+  ScopedLock scoped_lock(mutex_);
+  return filled_output_buffers_.empty() ? NULL : filled_output_buffers_.front();
+}
+
+void OpenMaxComponent::DropNextOutputBuffer() {
+  OMX_BUFFERHEADERTYPE* buffer = NULL;
+  {
+    ScopedLock scoped_lock(mutex_);
+    SB_DCHECK(!filled_output_buffers_.empty());
+    buffer = filled_output_buffers_.front();
+    filled_output_buffers_.pop();
+  }
+  buffer->nFilledLen = 0;
+  OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, buffer);
   SB_DCHECK(error == OMX_ErrorNone);
-  return true;
 }
 
 void OpenMaxComponent::SendCommand(OMX_COMMANDTYPE command, int param) {
@@ -234,48 +223,68 @@
 }
 
 void OpenMaxComponent::EnableInputPortAndAllocateBuffers() {
-  SB_DCHECK(unused_buffers_.empty());
+  SB_DCHECK(input_buffers_.empty());
 
   OMXParamPortDefinition port_definition;
   GetInputPortParam(&port_definition);
+  if (OnEnableInputPort(&port_definition)) {
+    SetPortParam(port_definition);
+  }
 
   SendCommand(OMX_CommandPortEnable, input_port_);
 
-  unused_buffers_.resize(port_definition.nBufferCountActual);
-  for (int i = 0; i != port_definition.nBufferCountActual; ++i) {
-    OMX_ERRORTYPE error =
-        OMX_AllocateBuffer(handle_, &unused_buffers_[i], input_port_, NULL,
-                           port_definition.nBufferSize);
+  for (int i = 0; i < port_definition.nBufferCountActual; ++i) {
+    OMX_BUFFERHEADERTYPE* buffer;
+    OMX_ERRORTYPE error = OMX_AllocateBuffer(handle_, &buffer, input_port_,
+                                             NULL, port_definition.nBufferSize);
     SB_DCHECK(error == OMX_ErrorNone);
+    input_buffers_.push_back(buffer);
+    unused_input_buffers_.push(buffer);
   }
 
   WaitForCommandCompletion();
 }
 
 void OpenMaxComponent::EnableOutputPortAndAllocateBuffer() {
-  if (output_buffer_ != NULL) {
-    return;
+  SB_DCHECK(!output_port_enabled_);
+
+  GetOutputPortParam(&output_port_definition_);
+  if (OnEnableOutputPort(&output_port_definition_)) {
+    SetPortParam(output_port_definition_);
   }
 
   SendCommand(OMX_CommandPortEnable, output_port_);
 
-  OMX_ERRORTYPE error = OMX_AllocateBuffer(
-      handle_, &output_buffer_, output_port_, NULL,
-      std::max(output_port_definition_.nBufferSize, minimum_output_size_));
-  SB_DCHECK(error == OMX_ErrorNone);
+  output_buffers_.reserve(output_port_definition_.nBufferCountActual);
+  for (int i = 0; i < output_port_definition_.nBufferCountActual; ++i) {
+    OMX_BUFFERHEADERTYPE* buffer;
+    OMX_ERRORTYPE error =
+        OMX_AllocateBuffer(handle_, &buffer, output_port_, NULL,
+                           output_port_definition_.nBufferSize);
+    SB_DCHECK(error == OMX_ErrorNone);
+    output_buffers_.push_back(buffer);
+  }
+
   WaitForCommandCompletion();
 
-  error = OMX_FillThisBuffer(handle_, output_buffer_);
-  SB_DCHECK(error == OMX_ErrorNone);
+  output_port_enabled_ = true;
+
+  for (size_t i = 0; i < output_buffers_.size(); ++i) {
+    output_buffers_[i]->nFilledLen = 0;
+    OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffers_[i]);
+    SB_DCHECK(error == OMX_ErrorNone);
+  }
 }
 
 OMX_BUFFERHEADERTYPE* OpenMaxComponent::GetUnusedInputBuffer() {
   for (;;) {
-    ScopedLock scoped_lock(mutex_);
-    if (!unused_buffers_.empty()) {
-      OMX_BUFFERHEADERTYPE* buffer_header = unused_buffers_.back();
-      unused_buffers_.pop_back();
-      return buffer_header;
+    {
+      ScopedLock scoped_lock(mutex_);
+      if (!unused_input_buffers_.empty()) {
+        OMX_BUFFERHEADERTYPE* buffer_header = unused_input_buffers_.front();
+        unused_input_buffers_.pop();
+        return buffer_header;
+      }
     }
     SbThreadSleep(kSbTimeMillisecond);
   }
@@ -312,13 +321,12 @@
 OMX_ERRORTYPE OpenMaxComponent::OnEmptyBufferDone(
     OMX_BUFFERHEADERTYPE* buffer) {
   ScopedLock scoped_lock(mutex_);
-  unused_buffers_.push_back(buffer);
+  unused_input_buffers_.push(buffer);
 }
 
 void OpenMaxComponent::OnFillBufferDone(OMX_BUFFERHEADERTYPE* buffer) {
   ScopedLock scoped_lock(mutex_);
-  SB_DCHECK(!output_buffer_filled_);
-  output_buffer_filled_ = true;
+  filled_output_buffers_.push(buffer);
 }
 
 // static
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.h b/src/starboard/raspi/shared/open_max/open_max_component.h
index 9085c1b..d9b5295 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.h
+++ b/src/starboard/raspi/shared/open_max/open_max_component.h
@@ -22,13 +22,14 @@
 #include <interface/vcos/vcos.h>
 #include <interface/vcos/vcos_logging.h>
 #include <interface/vmcs_host/vchost.h>
+
+#include <queue>
 #include <vector>
 
 #include "starboard/condition_variable.h"
 #include "starboard/log.h"
 #include "starboard/mutex.h"
 #include "starboard/shared/internal_only.h"
-#include "starboard/shared/starboard/player/video_frame_internal.h"
 #include "starboard/time.h"
 
 namespace starboard {
@@ -53,10 +54,8 @@
 
 class OpenMaxComponent {
  public:
-  typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
-
-  explicit OpenMaxComponent(const char* name, size_t minimum_output_size = 0);
-  ~OpenMaxComponent();
+  explicit OpenMaxComponent(const char* name);
+  virtual ~OpenMaxComponent();
 
   void Start();
   void Flush();
@@ -64,7 +63,8 @@
   void WriteData(const void* data, size_t size, SbTime timestamp);
   void WriteEOS();
 
-  bool ReadVideoFrame(VideoFrame* frame);
+  OMX_BUFFERHEADERTYPE* PeekNextOutputBuffer();
+  void DropNextOutputBuffer();
 
   template <typename ParamType>
   void GetInputPortParam(ParamType* param) const {
@@ -94,8 +94,6 @@
   }
 
  private:
-  typedef std::vector<OMX_BUFFERHEADERTYPE*> BufferHeaders;
-
   struct EventDescription {
     OMX_EVENTTYPE event;
     OMX_U32 data1;
@@ -105,6 +103,13 @@
 
   typedef std::vector<EventDescription> EventDescriptions;
 
+  virtual bool OnEnableInputPort(OMXParamPortDefinition* port_definition) {
+    return false;
+  }
+  virtual bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) {
+    return false;
+  }
+
   void SendCommand(OMX_COMMANDTYPE command, int param);
   void WaitForCommandCompletion();
   void SendCommandAndWaitForCompletion(OMX_COMMANDTYPE command, int param);
@@ -134,16 +139,18 @@
 
   Mutex mutex_;
   ConditionVariable condition_variable_;
-  const size_t minimum_output_size_;
   OMX_HANDLETYPE handle_;
   int input_port_;
   int output_port_;
   bool output_setting_changed_;
   EventDescriptions event_descriptions_;
-  BufferHeaders unused_buffers_;
-  OMX_BUFFERHEADERTYPE* output_buffer_;
+  std::vector<OMX_BUFFERHEADERTYPE*> input_buffers_;
+  std::queue<OMX_BUFFERHEADERTYPE*> unused_input_buffers_;
+  std::vector<OMX_BUFFERHEADERTYPE*> output_buffers_;
+  std::queue<OMX_BUFFERHEADERTYPE*> filled_output_buffers_;
+
   OMXParamPortDefinition output_port_definition_;
-  bool output_buffer_filled_;
+  bool output_port_enabled_;
 };
 
 }  // namespace open_max
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
new file mode 100644
index 0000000..0520c36
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
@@ -0,0 +1,165 @@
+// 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/raspi/shared/open_max/open_max_video_decode_component.h"
+
+#include <algorithm>
+
+#include "starboard/configuration.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+namespace {
+
+const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
+const size_t kResourcePoolSize = 12;
+const size_t kOMXOutputBufferCount = 4;
+const int kMaxFrameWidth = 1920;
+const int kMaxFrameHeight = 1088;
+const size_t kMaxVideoFrameSize = kMaxFrameWidth * kMaxFrameHeight * 3 / 2;
+
+}  // namespace
+
+typedef OpenMaxVideoDecodeComponent::VideoFrame VideoFrame;
+
+VideoFrameResourcePool::VideoFrameResourcePool(size_t max_number_of_resources)
+    : max_number_of_resources_(max_number_of_resources),
+      number_of_resources_(0),
+      last_frame_height_(0) {}
+
+VideoFrameResourcePool::~VideoFrameResourcePool() {
+  for (ResourceMap::iterator iter = resource_map_.begin();
+       iter != resource_map_.end(); ++iter) {
+    while (!iter->second.empty()) {
+      delete iter->second.front();
+      iter->second.pop();
+      --number_of_resources_;
+    }
+  }
+  SB_DCHECK(number_of_resources_ == 0) << number_of_resources_;
+}
+
+DispmanxYUV420Resource* VideoFrameResourcePool::Alloc(int width,
+                                                      int height,
+                                                      int visible_width,
+                                                      int visible_height) {
+  ScopedLock scoped_lock(mutex_);
+
+  last_frame_height_ = height;
+
+  ResourceMap::iterator iter = resource_map_.find(height);
+  if (iter != resource_map_.end() && !iter->second.empty()) {
+    DispmanxYUV420Resource* resource = iter->second.front();
+    iter->second.pop();
+    return resource;
+  }
+
+  if (number_of_resources_ >= max_number_of_resources_) {
+    return NULL;
+  }
+
+  ++number_of_resources_;
+  return new DispmanxYUV420Resource(width, height, visible_width,
+                                    visible_height);
+}
+
+void VideoFrameResourcePool::Free(DispmanxYUV420Resource* resource) {
+  ScopedLock scoped_lock(mutex_);
+  if (resource->height() != last_frame_height_) {
+    // The video has adapted, free the resource as it won't be reused any soon.
+    delete resource;
+    --number_of_resources_;
+    return;
+  }
+  resource_map_[resource->height()].push(resource);
+}
+
+// static
+void VideoFrameResourcePool::DisposeDispmanxYUV420Resource(
+    void* context,
+    void* dispmanx_resource) {
+  SB_DCHECK(context != NULL);
+  SB_DCHECK(dispmanx_resource != NULL);
+  VideoFrameResourcePool* pool =
+      reinterpret_cast<VideoFrameResourcePool*>(context);
+  pool->Free(reinterpret_cast<DispmanxYUV420Resource*>(dispmanx_resource));
+  pool->Release();
+}
+
+OpenMaxVideoDecodeComponent::OpenMaxVideoDecodeComponent()
+    : OpenMaxComponent(kVideoDecodeComponentName),
+      resource_pool_(new VideoFrameResourcePool(kResourcePoolSize)) {}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::ReadVideoFrame() {
+  if (OMX_BUFFERHEADERTYPE* buffer = PeekNextOutputBuffer()) {
+    if (scoped_refptr<VideoFrame> frame = CreateVideoFrame(buffer)) {
+      DropNextOutputBuffer();
+      return frame;
+    }
+  }
+  return NULL;
+}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::CreateVideoFrame(
+    OMX_BUFFERHEADERTYPE* buffer) {
+  scoped_refptr<VideoFrame> frame;
+  if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
+    frame = VideoFrame::CreateEOSFrame();
+  } else {
+    OMX_VIDEO_PORTDEFINITIONTYPE& video_definition =
+        output_port_definition_.format.video;
+    DispmanxYUV420Resource* resource = resource_pool_->Alloc(
+        video_definition.nStride, video_definition.nSliceHeight,
+        video_definition.nFrameWidth, video_definition.nFrameHeight);
+    if (!resource) {
+      return NULL;
+    }
+
+    resource->WriteData(buffer->pBuffer);
+
+    SbMediaTime timestamp = ((buffer->nTimeStamp.nHighPart * 0x100000000ull) +
+                             buffer->nTimeStamp.nLowPart) *
+                            kSbMediaTimeSecond / kSbTimeSecond;
+
+    resource_pool_->AddRef();
+    frame = new VideoFrame(
+        video_definition.nFrameWidth, video_definition.nFrameHeight, timestamp,
+        resource, resource_pool_,
+        &VideoFrameResourcePool::DisposeDispmanxYUV420Resource);
+  }
+  return frame;
+}
+
+bool OpenMaxVideoDecodeComponent::OnEnableOutputPort(
+    OMXParamPortDefinition* port_definition) {
+  SB_DCHECK(port_definition);
+
+  output_port_definition_ = *port_definition;
+  SB_DCHECK(port_definition->format.video.eColorFormat ==
+            OMX_COLOR_FormatYUV420PackedPlanar);
+  port_definition->format.video.eColorFormat =
+      OMX_COLOR_FormatYUV420PackedPlanar;
+  port_definition->nBufferCountActual = kOMXOutputBufferCount;
+  port_definition->nBufferSize =
+      std::max(port_definition->nBufferSize, kMaxVideoFrameSize);
+  return true;
+}
+
+}  // namespace open_max
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
new file mode 100644
index 0000000..94b9cda
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
@@ -0,0 +1,84 @@
+// 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_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+#define STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+
+#include <map>
+#include <queue>
+
+#include "starboard/common/ref_counted.h"
+#include "starboard/raspi/shared/dispmanx_util.h"
+#include "starboard/raspi/shared/open_max/open_max_component.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+class VideoFrameResourcePool
+    : public RefCountedThreadSafe<VideoFrameResourcePool> {
+ public:
+  explicit VideoFrameResourcePool(size_t max_number_of_resources);
+  ~VideoFrameResourcePool();
+
+  DispmanxYUV420Resource* Alloc(int width,
+                                int height,
+                                int visible_width,
+                                int visible_height);
+  void Free(DispmanxYUV420Resource* resource);
+
+  static void DisposeDispmanxYUV420Resource(void* context,
+                                            void* dispmanx_resource);
+
+ private:
+  typedef std::queue<DispmanxYUV420Resource*> ResourceQueue;
+  // Map frame height to resource handles.
+  typedef std::map<int, ResourceQueue> ResourceMap;
+
+  const size_t max_number_of_resources_;
+
+  Mutex mutex_;
+  size_t number_of_resources_;
+  int last_frame_height_;
+  ResourceMap resource_map_;
+};
+
+// Encapsulate a "OMX.broadcom.video_decode" component.  Note that member
+// functions of this class is expected to be called from ANY threads as this
+// class works with the VideoDecoder filter, the OpenMAX component, and also
+// manages the disposition of Dispmanx resource.
+class OpenMaxVideoDecodeComponent : public OpenMaxComponent {
+ public:
+  typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
+
+  OpenMaxVideoDecodeComponent();
+
+  scoped_refptr<VideoFrame> ReadVideoFrame();
+
+ private:
+  scoped_refptr<VideoFrame> CreateVideoFrame(OMX_BUFFERHEADERTYPE* buffer);
+
+  bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) SB_OVERRIDE;
+
+  scoped_refptr<VideoFrameResourcePool> resource_pool_;
+  OMXParamPortDefinition output_port_definition_;
+};
+
+}  // namespace open_max
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
+
+#endif  // STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.cc b/src/starboard/raspi/shared/open_max/video_decoder.cc
index 702a9f8..a238db7 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.cc
+++ b/src/starboard/raspi/shared/open_max/video_decoder.cc
@@ -23,17 +23,8 @@
 
 using starboard::shared::starboard::player::VideoFrame;
 
-namespace {
-
-const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
-const size_t kMaxVideoFrameSize = 1920 * 1088 * 3 / 2;
-
-}  // namespace
-
 VideoDecoder::VideoDecoder(SbMediaVideoCodec video_codec)
-    : component_(kVideoDecodeComponentName, kMaxVideoFrameSize),
-      host_(NULL),
-      stream_ended_(false) {
+    : host_(NULL), stream_ended_(false) {
   SB_DCHECK(video_codec == kSbMediaVideoCodecH264);
 
   OMXVideoParamPortFormat port_format;
@@ -61,11 +52,11 @@
   }
   component_.WriteData(input_buffer.data(), input_buffer.size(),
                        input_buffer.pts() * kSbTimeSecond / kSbMediaTimeSecond);
-
-  VideoFrame frame;
-  if (component_.ReadVideoFrame(&frame)) {
-    host_->OnDecoderStatusUpdate(kNeedMoreInput, &frame);
+  if (scoped_refptr<VideoFrame> frame = component_.ReadVideoFrame()) {
+    host_->OnDecoderStatusUpdate(kNeedMoreInput, frame);
   } else {
+    // Call the callback with NULL frame to ensure that the host know that more
+    // data is expected.
     host_->OnDecoderStatusUpdate(kNeedMoreInput, NULL);
   }
 }
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.h b/src/starboard/raspi/shared/open_max/video_decoder.h
index 92850da..de684af 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.h
+++ b/src/starboard/raspi/shared/open_max/video_decoder.h
@@ -16,7 +16,7 @@
 #define STARBOARD_RASPI_SHARED_OPEN_MAX_VIDEO_DECODER_H_
 
 #include "starboard/media.h"
-#include "starboard/raspi/shared/open_max/open_max_component.h"
+#include "starboard/raspi/shared/open_max/open_max_video_decode_component.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
 
@@ -39,7 +39,7 @@
   void Reset() SB_OVERRIDE;
 
  private:
-  OpenMaxComponent component_;
+  OpenMaxVideoDecodeComponent component_;
 
   // These variables will be initialized inside ctor or SetHost() and will not
   // be changed during the life time of this class.
diff --git a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
index ba9d317..2f9505b 100644
--- a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
+++ b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
@@ -26,5 +26,7 @@
 
   swap_chain->render_target.surface->Release(swap_chain->render_target.surface);
 
+  delete swap_chain;
+
   return true;
 }
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index 7b9efed..2e05ee8 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -197,8 +197,7 @@
         packet.pts = 0;
       } while (DecodePacket(&packet));
 
-      VideoFrame frame = VideoFrame::CreateEOSFrame();
-      host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+      host_->OnDecoderStatusUpdate(kBufferFull, VideoFrame::CreateEOSFrame());
     }
   }
 }
@@ -223,11 +222,11 @@
 
   int pitch = AlignUp(av_frame_->width, kAlignment * 2);
 
-  VideoFrame frame = VideoFrame::CreateYV12Frame(
+  scoped_refptr<VideoFrame> frame = VideoFrame::CreateYV12Frame(
       av_frame_->width, av_frame_->height, pitch,
       codec_context_->reordered_opaque, av_frame_->data[0], av_frame_->data[1],
       av_frame_->data[2]);
-  host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+  host_->OnDecoderStatusUpdate(kBufferFull, frame);
   return true;
 }
 
diff --git a/src/starboard/shared/posix/socket_receive_from.cc b/src/starboard/shared/posix/socket_receive_from.cc
index c4819b6..ca0cb04 100644
--- a/src/starboard/shared/posix/socket_receive_from.cc
+++ b/src/starboard/shared/posix/socket_receive_from.cc
@@ -27,11 +27,7 @@
                         char* out_data,
                         int data_size,
                         SbSocketAddress* out_source) {
-#if defined(MSG_NOSIGNAL)
-  const int kRecvFlags = MSG_NOSIGNAL;
-#else
   const int kRecvFlags = 0;
-#endif
 
   if (!SbSocketIsValid(socket)) {
     errno = EBADF;
diff --git a/src/starboard/shared/signal/crash_signals.cc b/src/starboard/shared/signal/crash_signals.cc
index 0d74011..78b3ab2 100644
--- a/src/starboard/shared/signal/crash_signals.cc
+++ b/src/starboard/shared/signal/crash_signals.cc
@@ -32,7 +32,7 @@
 };
 
 const int kStopSignalsToTrap[] = {
-    SIGTERM, SIGINT, SIGHUP,
+    SIGHUP,
 };
 
 void Crash(int signal_id) {
diff --git a/src/starboard/shared/signal/crash_signals_sigaction.cc b/src/starboard/shared/signal/crash_signals_sigaction.cc
index 5273ab1..da318a8 100644
--- a/src/starboard/shared/signal/crash_signals_sigaction.cc
+++ b/src/starboard/shared/signal/crash_signals_sigaction.cc
@@ -32,7 +32,7 @@
 };
 
 const int kStopSignalsToTrap[] = {
-    SIGTERM, SIGINT, SIGHUP,
+    SIGHUP,
 };
 
 void SetSignalHandler(int signal_id, SignalHandlerFunction handler) {
diff --git a/src/starboard/shared/signal/suspend_signals.cc b/src/starboard/shared/signal/suspend_signals.cc
index 6bb42d8..4048a3b 100644
--- a/src/starboard/shared/signal/suspend_signals.cc
+++ b/src/starboard/shared/signal/suspend_signals.cc
@@ -15,6 +15,7 @@
 #include "starboard/shared/signal/suspend_signals.h"
 
 #include <signal.h>
+#include <sys/socket.h>
 
 #include "starboard/configuration.h"
 #include "starboard/log.h"
@@ -71,19 +72,34 @@
 
 }  // namespace
 
+#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
+// See "#if !defined(MSG_NOSIGNAL)" below.
+// OS X, which we do not build for today, has another mechanism which
+// should be used.
+#error On this platform, please use SO_NOSIGPIPE and leave the SIGPIPE \
+       handler at default.
+#endif
+
 void InstallSuspendSignalHandlers() {
   SetSignalHandler(SIGTSTP, &Suspend);
   UnblockSignal(SIGTSTP);
   SetSignalHandler(SIGCONT, &Resume);
 
-  // We might receive SIGPIPE after resuming. We should not terminate.
+#if !defined(MSG_NOSIGNAL)
+  // By default in POSIX, sending to a closed socket causes a SIGPIPE
+  // If we cannot disable that behavior, we must ignore SIGPIPE.
+  // Ignoring SIGPIPE means cases that use pipes to redirect the stdio
+  // log messages may behave in surprising ways, so it's not desirable.
   SetSignalHandler(SIGPIPE, &Ignore);
+#endif
 }
 
 void UninstallSuspendSignalHandlers() {
   SetSignalHandler(SIGCONT, SIG_DFL);
   SetSignalHandler(SIGTSTP, SIG_DFL);
+#if !defined(MSG_NOSIGNAL)
   SetSignalHandler(SIGPIPE, SIG_DFL);
+#endif
 }
 
 }  // namespace signal
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 96efbdb..4f2e850 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -130,7 +130,7 @@
 
 #if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
 void Application::HandleFrame(SbPlayer player,
-                              const VideoFrame& frame,
+                              const scoped_refptr<VideoFrame>& frame,
                               int x,
                               int y,
                               int width,
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index f8609ce..4387bed 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -202,7 +202,7 @@
   // used when the application needs to composite video frames with punch-out
   // video manually (should be rare). Will be called from an external thread.
   void HandleFrame(SbPlayer player,
-                   const VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
@@ -224,7 +224,7 @@
   // Subclasses may override this method to accept video frames from the media
   // system. Will be called from an external thread.
   virtual void AcceptFrame(SbPlayer player,
-                           const VideoFrame& frame,
+                           const scoped_refptr<VideoFrame>& frame,
                            int x,
                            int y,
                            int width,
diff --git a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
index 3317806..8648663 100644
--- a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
+++ b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
@@ -248,9 +248,11 @@
     }
   }
 
-  return SbBlitterBlitRectsToRects(context, source_surface, src_rects,
-                                   dst_rects, num_tiles);
+  bool result = SbBlitterBlitRectsToRects(context, source_surface, src_rects,
+                                          dst_rects, num_tiles);
 
   delete[] src_rects;
   delete[] dst_rects;
+
+  return result;
 }
diff --git a/src/starboard/shared/starboard/file_storage/storage_internal.h b/src/starboard/shared/starboard/file_storage/storage_internal.h
index ea322b8..6bb3362 100644
--- a/src/starboard/shared/starboard/file_storage/storage_internal.h
+++ b/src/starboard/shared/starboard/file_storage/storage_internal.h
@@ -33,9 +33,9 @@
 namespace shared {
 namespace starboard {
 // Gets the path to the storage file for the given user.
-SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
-                                        char* out_path,
-                                        int path_size) {
+static SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
+                                               char* out_path,
+                                               int path_size) {
   bool success = SbUserGetProperty(user, kSbUserPropertyHomeDirectory, out_path,
                                    path_size);
   if (!success) {
diff --git a/src/starboard/shared/starboard/localized_strings.cc b/src/starboard/shared/starboard/localized_strings.cc
index 2639c53..0f802e6 100644
--- a/src/starboard/shared/starboard/localized_strings.cc
+++ b/src/starboard/shared/starboard/localized_strings.cc
@@ -116,7 +116,7 @@
     return false;
   }
   SB_DCHECK(file_contents.length() > 0);
-  SB_DCHECK(file_contents.back() == '\n');
+  SB_DCHECK(file_contents[file_contents.length() - 1] == '\n');
 
   // Each line of the file corresponds to one message (key/value).
   size_t pos = 0;
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 54477cf..b73cbb2 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -210,7 +210,7 @@
       (*player_worker_.*update_player_state_cb_)(kSbPlayerStateEndOfStream);
     }
 
-    const VideoFrame& frame =
+    scoped_refptr<VideoFrame> frame =
         video_renderer_->GetCurrentFrame(audio_renderer_->GetCurrentTime());
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
@@ -230,8 +230,8 @@
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
   // Clear the video frame as we terminate.
-  shared::starboard::Application::Get()->HandleFrame(player_, VideoFrame(), 0,
-                                                     0, 0, 0);
+  shared::starboard::Application::Get()->HandleFrame(
+      player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 }
 
diff --git a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
index fd32c9f..e55c685 100644
--- a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
@@ -37,7 +37,9 @@
     // user should only call WriteInputFrame() when |status| is kNeedMoreInput
     // or when the instance is just created.  Also note that calling Reset() or
     // dtor from this callback will result in deadlock.
-    virtual void OnDecoderStatusUpdate(Status status, VideoFrame* frame) = 0;
+    virtual void OnDecoderStatusUpdate(
+        Status status,
+        const scoped_refptr<VideoFrame>& frame) = 0;
 
    protected:
     ~Host() {}
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
index 65ee800..35b6bf0 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
@@ -79,7 +79,8 @@
   frames_.clear();
 }
 
-const VideoFrame& VideoRenderer::GetCurrentFrame(SbMediaTime media_time) {
+scoped_refptr<VideoFrame> VideoRenderer::GetCurrentFrame(
+    SbMediaTime media_time) {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
 
   if (frames_.empty()) {
@@ -87,7 +88,7 @@
   }
   // Remove any frames with timestamps earlier than |media_time|, but always
   // keep at least one of the frames.
-  while (frames_.size() > 1 && frames_.front().pts() < media_time) {
+  while (frames_.size() > 1 && frames_.front()->pts() < media_time) {
     frames_.pop_front();
   }
 
@@ -101,6 +102,7 @@
 
 bool VideoRenderer::CanAcceptMoreData() const {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
+  ScopedLock lock(mutex_);
   return frames_.size() < kMaxCachedFrames && !end_of_stream_written_ &&
          need_more_input_;
 }
@@ -110,8 +112,9 @@
   return seeking_;
 }
 
-void VideoRenderer::OnDecoderStatusUpdate(VideoDecoder::Status status,
-                                          VideoFrame* frame) {
+void VideoRenderer::OnDecoderStatusUpdate(
+    VideoDecoder::Status status,
+    const scoped_refptr<VideoFrame>& frame) {
   ScopedLock lock(mutex_);
 
   if (frame) {
@@ -124,7 +127,7 @@
       }
     }
     if (!frame_too_early) {
-      frames_.push_back(*frame);
+      frames_.push_back(frame);
     }
 
     if (seeking_ && frames_.size() >= kPrerollFrames) {
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
index 8450e59..6cc4cad 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
@@ -44,7 +44,7 @@
 
   void Seek(SbMediaTime seek_to_pts);
 
-  const VideoFrame& GetCurrentFrame(SbMediaTime media_time);
+  scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time);
 
   bool IsEndOfStreamWritten() const { return end_of_stream_written_; }
   bool IsEndOfStreamPlayed() const;
@@ -52,7 +52,7 @@
   bool IsSeekingInProgress() const;
 
  private:
-  typedef std::list<VideoFrame> Frames;
+  typedef std::list<scoped_refptr<VideoFrame> > Frames;
 
   // Preroll considered finished after either kPrerollFrames is cached or EOS
   // is reached.
@@ -65,7 +65,8 @@
 
   // VideoDecoder::Host method.
   void OnDecoderStatusUpdate(VideoDecoder::Status status,
-                             VideoFrame* frame) SB_OVERRIDE;
+                             const scoped_refptr<VideoFrame>& frame)
+      SB_OVERRIDE;
 
   ThreadChecker thread_checker_;
   ::starboard::Mutex mutex_;
@@ -77,7 +78,7 @@
   // should still display the last frame it is rendering.  This frame will be
   // kept inside |seeking_frame_|.  It is an empty/black frame before the video
   // is started.
-  VideoFrame seeking_frame_;
+  scoped_refptr<VideoFrame> seeking_frame_;
 
   SbMediaTime seeking_to_pts_;
   bool end_of_stream_written_;
diff --git a/src/starboard/shared/starboard/player/video_frame_internal.cc b/src/starboard/shared/starboard/player/video_frame_internal.cc
index 793066d..7bee2c4 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.cc
+++ b/src/starboard/shared/starboard/player/video_frame_internal.cc
@@ -73,53 +73,76 @@
 

 }  // namespace

 

-VideoFrame::VideoFrame(const VideoFrame& that) {

-  *this = that;

+VideoFrame::VideoFrame() {

+  InitializeToInvalidFrame();

 }

 

-VideoFrame& VideoFrame::operator=(const VideoFrame& that) {

-  this->format_ = that.format_;

+VideoFrame::VideoFrame(int width,

+                       int height,

+                       SbMediaTime pts,

+                       void* native_texture,

+                       void* native_texture_context,

+                       FreeNativeTextureFunc free_native_texture_func) {

+  SB_DCHECK(native_texture != NULL);

+  SB_DCHECK(free_native_texture_func != NULL);

 

-  this->pts_ = that.pts_;

-  this->planes_ = that.planes_;

-  this->pixel_buffer_ = that.pixel_buffer_;

+  InitializeToInvalidFrame();

 

-  for (int i = 0; i < GetPlaneCount(); ++i) {

-    const uint8_t* data = that.GetPlane(i).data;

-    const uint8_t* base = &that.pixel_buffer_[0];

-    ptrdiff_t offset = data - base;

-    SB_DCHECK(offset >= 0);

-    SB_DCHECK(offset < static_cast<ptrdiff_t>(that.pixel_buffer_.size()));

-    planes_[i].data = &pixel_buffer_[0] + offset;

+  format_ = kNativeTexture;

+  width_ = width;

+  height_ = height;

+  pts_ = pts;

+  native_texture_ = native_texture;

+  native_texture_context_ = native_texture_context;

+  free_native_texture_func_ = free_native_texture_func;

+}

+

+VideoFrame::~VideoFrame() {

+  if (format_ == kNativeTexture) {

+    free_native_texture_func_(native_texture_context_, native_texture_);

   }

+}

 

-  return *this;

+int VideoFrame::GetPlaneCount() const {

+  SB_DCHECK(format_ != kInvalid);

+  SB_DCHECK(format_ != kNativeTexture);

+

+  return static_cast<int>(planes_.size());

 }

 

 const VideoFrame::Plane& VideoFrame::GetPlane(int index) const {

+  SB_DCHECK(format_ != kInvalid);

+  SB_DCHECK(format_ != kNativeTexture);

   SB_DCHECK(index >= 0 && index < GetPlaneCount()) << "Invalid index: "

                                                    << index;

   return planes_[index];

 }

 

-VideoFrame VideoFrame::ConvertTo(Format target_format) const {

+void* VideoFrame::native_texture() const {

+  SB_DCHECK(format_ == kNativeTexture);

+  return native_texture_;

+}

+

+scoped_refptr<VideoFrame> VideoFrame::ConvertTo(Format target_format) const {

   SB_DCHECK(format_ == kYV12);

   SB_DCHECK(target_format == kBGRA32);

 

   EnsureYUVToRGBLookupTableInitialized();

 

-  VideoFrame target_frame;

+  scoped_refptr<VideoFrame> target_frame(new VideoFrame);

 

-  target_frame.format_ = target_format;

-  target_frame.pts_ = pts_;

-  target_frame.pixel_buffer_.resize(width() * height() * 4);

-  target_frame.planes_.push_back(

-      Plane(width(), height(), width() * 4, &target_frame.pixel_buffer_[0]));

+  target_frame->format_ = target_format;

+  target_frame->width_ = width();

+  target_frame->height_ = height();

+  target_frame->pts_ = pts_;

+  target_frame->pixel_buffer_.reset(new uint8_t[width() * height() * 4]);

+  target_frame->planes_.push_back(

+      Plane(width(), height(), width() * 4, target_frame->pixel_buffer_.get()));

 

   const uint8_t* y_data = GetPlane(0).data;

   const uint8_t* u_data = GetPlane(1).data;

   const uint8_t* v_data = GetPlane(2).data;

-  uint8_t* bgra_data = &target_frame.pixel_buffer_[0];

+  uint8_t* bgra_data = target_frame->pixel_buffer_.get();

 

   int height = this->height();

   int width = this->width();

@@ -158,21 +181,23 @@
 }

 

 // static

-VideoFrame VideoFrame::CreateEOSFrame() {

-  return VideoFrame();

+scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {

+  return new VideoFrame;

 }

 

 // static

-VideoFrame VideoFrame::CreateYV12Frame(int width,

-                                       int height,

-                                       int pitch_in_bytes,

-                                       SbMediaTime pts,

-                                       const uint8_t* y,

-                                       const uint8_t* u,

-                                       const uint8_t* v) {

-  VideoFrame frame;

-  frame.format_ = kYV12;

-  frame.pts_ = pts;

+scoped_refptr<VideoFrame> VideoFrame::CreateYV12Frame(int width,

+                                                      int height,

+                                                      int pitch_in_bytes,

+                                                      SbMediaTime pts,

+                                                      const uint8_t* y,

+                                                      const uint8_t* u,

+                                                      const uint8_t* v) {

+  scoped_refptr<VideoFrame> frame(new VideoFrame);

+  frame->format_ = kYV12;

+  frame->width_ = width;

+  frame->height_ = height;

+  frame->pts_ = pts;

 

   // U/V planes generally have half resolution of the Y plane.  However, in the

   // extreme case that any dimension of Y plane is odd, we want to have an

@@ -183,26 +208,38 @@
 

   int y_plane_size_in_bytes = height * pitch_in_bytes;

   int uv_plane_size_in_bytes = uv_height * uv_pitch_in_bytes;

-  frame.pixel_buffer_.reserve(y_plane_size_in_bytes +

-                              uv_plane_size_in_bytes * 2);

-  frame.pixel_buffer_.assign(y, y + y_plane_size_in_bytes);

-  frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), u,

-                             u + uv_plane_size_in_bytes);

-  frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), v,

-                             v + uv_plane_size_in_bytes);

+  frame->pixel_buffer_.reset(

+      new uint8_t[y_plane_size_in_bytes + uv_plane_size_in_bytes * 2]);

+  SbMemoryCopy(frame->pixel_buffer_.get(), y, y_plane_size_in_bytes);

+  SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes, u,

+               uv_plane_size_in_bytes);

+  SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes +

+                   uv_plane_size_in_bytes,

+               v, uv_plane_size_in_bytes);

 

-  frame.planes_.push_back(

-      Plane(width, height, pitch_in_bytes, &frame.pixel_buffer_[0]));

-  frame.planes_.push_back(

+  frame->planes_.push_back(

+      Plane(width, height, pitch_in_bytes, frame->pixel_buffer_.get()));

+  frame->planes_.push_back(

       Plane(uv_width, uv_height, uv_pitch_in_bytes,

-            &frame.pixel_buffer_[0] + y_plane_size_in_bytes));

-  frame.planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,

-                                &frame.pixel_buffer_[0] +

-                                    y_plane_size_in_bytes +

-                                    uv_plane_size_in_bytes));

+            frame->pixel_buffer_.get() + y_plane_size_in_bytes));

+  frame->planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,

+                                 frame->pixel_buffer_.get() +

+                                     y_plane_size_in_bytes +

+                                     uv_plane_size_in_bytes));

   return frame;

 }

 

+void VideoFrame::InitializeToInvalidFrame() {

+  format_ = kInvalid;

+  width_ = 0;

+  height_ = 0;

+

+  pts_ = 0;

+  native_texture_ = NULL;

+  native_texture_context_ = NULL;

+  free_native_texture_func_ = NULL;

+}

+

 }  // namespace player

 }  // namespace starboard

 }  // namespace shared

diff --git a/src/starboard/shared/starboard/player/video_frame_internal.h b/src/starboard/shared/starboard/player/video_frame_internal.h
index 745ec31..c956e90 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.h
+++ b/src/starboard/shared/starboard/player/video_frame_internal.h
@@ -17,6 +17,9 @@
 

 #include <vector>

 

+#include "starboard/common/ref_counted.h"

+#include "starboard/common/scoped_ptr.h"

+#include "starboard/configuration.h"

 #include "starboard/media.h"

 #include "starboard/shared/internal_only.h"

 

@@ -26,10 +29,12 @@
 namespace player {

 

 // A video frame produced by a video decoder.

-class VideoFrame {

+class VideoFrame : public RefCountedThreadSafe<VideoFrame> {

  public:

+  typedef void (*FreeNativeTextureFunc)(void* context, void* textue);

+

   enum Format {

-    kInvalid,

+    kInvalid,  // A VideoFrame in this format can be used to indicate EOS.

     // This is the native format supported by XComposite (PictStandardARGB32

     // with bytes swapped).  Remove this once we are able to pass out frames

     // as YV12 textures.

@@ -50,37 +55,55 @@
     const uint8_t* data;

   };

 

-  VideoFrame() : format_(kInvalid) {}

-  VideoFrame(const VideoFrame& that);

-

-  VideoFrame& operator=(const VideoFrame& that);

+  VideoFrame();  // Create an EOS frame.

+  VideoFrame(int width,

+             int height,

+             SbMediaTime pts,

+             void* native_texture,

+             void* native_texture_context,

+             FreeNativeTextureFunc free_native_texture_func);

+  ~VideoFrame();

 

   Format format() const { return format_; }

-  int width() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).width; }

-  int height() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).height; }

-

   bool IsEndOfStream() const { return format_ == kInvalid; }

   SbMediaTime pts() const { return pts_; }

-  int GetPlaneCount() const { return static_cast<int>(planes_.size()); }

+  int width() const { return width_; }

+  int height() const { return height_; }

+

+  int GetPlaneCount() const;

   const Plane& GetPlane(int index) const;

 

-  VideoFrame ConvertTo(Format target_format) const;

+  void* native_texture() const;

 

-  static VideoFrame CreateEOSFrame();

-  static VideoFrame CreateYV12Frame(int width,

-                                    int height,

-                                    int pitch_in_bytes,

-                                    SbMediaTime pts,

-                                    const uint8_t* y,

-                                    const uint8_t* u,

-                                    const uint8_t* v);

+  scoped_refptr<VideoFrame> ConvertTo(Format target_format) const;

+

+  static scoped_refptr<VideoFrame> CreateEOSFrame();

+  static scoped_refptr<VideoFrame> CreateYV12Frame(int width,

+                                                   int height,

+                                                   int pitch_in_bytes,

+                                                   SbMediaTime pts,

+                                                   const uint8_t* y,

+                                                   const uint8_t* u,

+                                                   const uint8_t* v);

 

  private:

-  Format format_;

+  void InitializeToInvalidFrame();

 

+  Format format_;

+  int width_;

+  int height_;

   SbMediaTime pts_;

+

+  // The following two variables are valid when the frame contains pixel data.

   std::vector<Plane> planes_;

-  std::vector<uint8_t> pixel_buffer_;

+  scoped_array<uint8_t> pixel_buffer_;

+

+  // The following three variables are valid when |format_| is `kNativeTexture`.

+  void* native_texture_;

+  void* native_texture_context_;

+  FreeNativeTextureFunc free_native_texture_func_;

+

+  SB_DISALLOW_COPY_AND_ASSIGN(VideoFrame);

 };

 

 }  // namespace player

diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index 1457e73..797c807 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -679,7 +679,7 @@
         ScopedLock lock(frame_mutex_);
         if (frame_written_) {
           // Clear the old frame, now that we are done with it.
-          frame_infos_[frame_read_index_].frame = VideoFrame();
+          frame_infos_[frame_read_index_].frame = NULL;
 
           // Increment the index to the next frame, which has been written.
           frame_read_index_ = (frame_read_index_ + 1) % kNumFrames;
@@ -692,12 +692,12 @@
       }
       FrameInfo& frame_info = frame_infos_[frame_read_index_];
 
-      if (!frame_info.frame.IsEndOfStream() &&
-          frame_info.frame.format() != VideoFrame::kBGRA32) {
-        frame_info.frame = frame_info.frame.ConvertTo(VideoFrame::kBGRA32);
+      if (frame_info.frame && !frame_info.frame->IsEndOfStream() &&
+          frame_info.frame->format() != VideoFrame::kBGRA32) {
+        frame_info.frame = frame_info.frame->ConvertTo(VideoFrame::kBGRA32);
       }
       window->Composite(frame_info.x, frame_info.y, frame_info.width,
-                        frame_info.height, &frame_info.frame);
+                        frame_info.height, frame_info.frame);
     }
   }
   composite_event_id_ =
@@ -705,7 +705,7 @@
 }
 
 void ApplicationX11::AcceptFrame(SbPlayer player,
-                                 const VideoFrame& frame,
+                                 const scoped_refptr<VideoFrame>& frame,
                                  int x,
                                  int y,
                                  int width,
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index 8bd9940..efe2a24 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -49,7 +49,7 @@
 
  protected:
   void AcceptFrame(SbPlayer player,
-                   const shared::starboard::player::VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
@@ -71,7 +71,7 @@
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
   struct FrameInfo {
-    shared::starboard::player::VideoFrame frame;
+    scoped_refptr<VideoFrame> frame;
     int x;
     int y;
     int width;
diff --git a/src/starboard/shared/x11/window_internal.cc b/src/starboard/shared/x11/window_internal.cc
index b17082a..70daeb3 100644
--- a/src/starboard/shared/x11/window_internal.cc
+++ b/src/starboard/shared/x11/window_internal.cc
@@ -30,8 +30,6 @@
 #include <X11/extensions/Xrender.h>
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 
-using starboard::shared::starboard::player::VideoFrame;
-
 namespace {
 
 const int kWindowWidth = 1920;
@@ -148,11 +146,12 @@
 }
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
-void SbWindowPrivate::Composite(int bounds_x,
-                                int bounds_y,
-                                int bounds_width,
-                                int bounds_height,
-                                VideoFrame* frame) {
+void SbWindowPrivate::Composite(
+    int bounds_x,
+    int bounds_y,
+    int bounds_width,
+    int bounds_height,
+    const starboard::scoped_refptr<VideoFrame>& frame) {
   XSynchronize(display, True);
   XWindowAttributes window_attributes;
   XGetWindowAttributes(display, window, &window_attributes);
diff --git a/src/starboard/shared/x11/window_internal.h b/src/starboard/shared/x11/window_internal.h
index 7c55cb3..e96ffdc 100644
--- a/src/starboard/shared/x11/window_internal.h
+++ b/src/starboard/shared/x11/window_internal.h
@@ -33,6 +33,8 @@
   Window window;
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
+  typedef ::starboard::shared::starboard::player::VideoFrame VideoFrame;
+
   // Composites graphics and the given video frame video for this window. In
   // PLAYER_PUNCHED_OUT mode, this is the only way any graphics or video is
   // presented in the window.  The video frame will be rendered according to
@@ -41,7 +43,7 @@
                  int bounds_y,
                  int bounds_width,
                  int bounds_height,
-                 ::starboard::shared::starboard::player::VideoFrame* frame);
+                 const starboard::scoped_refptr<VideoFrame>& frame);
 
   // The cached XRender Picture that represents the window that is the
   // destination of the composition.
diff --git a/src/starboard/thread.h b/src/starboard/thread.h
index d2138e0..f642f28 100644
--- a/src/starboard/thread.h
+++ b/src/starboard/thread.h
@@ -255,7 +255,7 @@
 // Returns whether |thread| is the current thread.
 //
 // |thread|: The thread to check.
-SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
+static SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
   return SbThreadGetCurrent() == thread;
 }
 
diff --git a/src/third_party/glm/glm/detail/setup.hpp b/src/third_party/glm/glm/detail/setup.hpp
index 0d524b2..349dbfa 100644
--- a/src/third_party/glm/glm/detail/setup.hpp
+++ b/src/third_party/glm/glm/detail/setup.hpp
@@ -305,7 +305,9 @@
 #endif
 
 // N1988
-#if GLM_LANG & GLM_LANG_CXX11_FLAG
+#if defined(STARBOARD)
+#	define GLM_HAS_EXTENDED_INTEGER_TYPE 0
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
 #	define GLM_HAS_EXTENDED_INTEGER_TYPE 1
 #else
 #	define GLM_HAS_EXTENDED_INTEGER_TYPE (\
diff --git a/src/third_party/glm/glm/detail/type_int.hpp b/src/third_party/glm/glm/detail/type_int.hpp
index 764a32c..f37a40a 100644
--- a/src/third_party/glm/glm/detail/type_int.hpp
+++ b/src/third_party/glm/glm/detail/type_int.hpp
@@ -4,6 +4,11 @@
 #pragma once
 
 #include "setup.hpp"
+
+#if defined(STARBOARD)
+#include "starboard/types.h"
+
+#else  // defined(STARBOARD)
 #if GLM_HAS_MAKE_SIGNED
 #	include <type_traits>
 #endif
@@ -11,11 +16,22 @@
 #if GLM_HAS_EXTENDED_INTEGER_TYPE
 #	include <cstdint>
 #endif
+#endif  // defined(STARBOARD)
 
 namespace glm{
 namespace detail
 {
-#	if GLM_HAS_EXTENDED_INTEGER_TYPE
+# if defined(STARBOARD)
+		typedef int8_t				int8;
+		typedef int16_t				int16;
+		typedef int32_t				int32;
+		typedef int64_t				int64;
+
+		typedef uint8_t				uint8;
+		typedef uint16_t			uint16;
+		typedef uint32_t			uint32;
+		typedef uint64_t			uint64;
+# elif GLM_HAS_EXTENDED_INTEGER_TYPE
 		typedef std::int8_t					int8;
 		typedef std::int16_t				int16;
 		typedef std::int32_t				int32;
diff --git a/src/third_party/glm/glm/fwd.hpp b/src/third_party/glm/glm/fwd.hpp
index f90c4d0..2e04473 100644
--- a/src/third_party/glm/glm/fwd.hpp
+++ b/src/third_party/glm/glm/fwd.hpp
@@ -257,7 +257,9 @@
 	typedef detail::int64 int64;
 
 
-#if GLM_HAS_EXTENDED_INTEGER_TYPE
+#if defined(STARBOARD)
+	// Empty.
+#elif GLM_HAS_EXTENDED_INTEGER_TYPE
 	using std::int8_t;
 	using std::int16_t;
 	using std::int32_t;
@@ -866,7 +868,9 @@
 	/// @see gtc_type_precision
 	typedef detail::uint64 uint64;
 	
-#if GLM_HAS_EXTENDED_INTEGER_TYPE
+#if defined(STARBOARD)
+	// Empty.
+#elif GLM_HAS_EXTENDED_INTEGER_TYPE
 	using std::uint8_t;
 	using std::uint16_t;
 	using std::uint32_t;
diff --git a/src/third_party/libxml/src/HTMLparser.c b/src/third_party/libxml/src/HTMLparser.c
index 3cb0388..c7a0658 100644
--- a/src/third_party/libxml/src/HTMLparser.c
+++ b/src/third_party/libxml/src/HTMLparser.c
@@ -3254,12 +3254,17 @@
 	ctxt->instate = state;
 	return;
     }
+    len = 0;
+    buf[len] = 0;
     q = CUR_CHAR(ql);
+    if (!IS_CHAR(q))
+        goto unfinished;
     NEXTL(ql);
     r = CUR_CHAR(rl);
+    if (!IS_CHAR(r))
+        goto unfinished;
     NEXTL(rl);
     cur = CUR_CHAR(l);
-    len = 0;
     while (IS_CHAR(cur) &&
            ((cur != '>') ||
 	    (r != '-') || (q != '-'))) {
@@ -3290,18 +3295,19 @@
 	}
     }
     buf[len] = 0;
-    if (!IS_CHAR(cur)) {
-	htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
-	             "Comment not terminated \n<!--%.50s\n", buf, NULL);
-	xmlFree(buf);
-    } else {
+    if (IS_CHAR(cur)) {
         NEXT;
 	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
 	    (!ctxt->disableSAX))
 	    ctxt->sax->comment(ctxt->userData, buf);
 	xmlFree(buf);
+	ctxt->instate = state;
+	return;
     }
-    ctxt->instate = state;
+unfinished:
+   htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
+		 "Comment not terminated \n<!--%.50s\n", buf, NULL);
+    xmlFree(buf);
 }
 
 /**
diff --git a/src/third_party/mozjs-45/INSTALL b/src/third_party/mozjs-45/INSTALL
new file mode 100644
index 0000000..c57135b
--- /dev/null
+++ b/src/third_party/mozjs-45/INSTALL
@@ -0,0 +1,13 @@
+Full build documentation for SpiderMonkey is hosted on MDN:
+  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Build_Documentation
+
+Note that the libraries produced by the build system include symbols,
+causing the binaries to be extremely large. It is highly suggested that `strip`
+be run over the binaries before deploying them.
+
+Building with default options may be performed as follows:
+  cd js/src
+  mkdir obj
+  cd obj
+  ../configure
+  make # or mozmake on Windows
diff --git a/src/third_party/mozjs-45/LICENSE b/src/third_party/mozjs-45/LICENSE
new file mode 100644
index 0000000..14e2f77
--- /dev/null
+++ b/src/third_party/mozjs-45/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in 
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff --git a/src/third_party/mozjs-45/Makefile.in b/src/third_party/mozjs-45/Makefile.in
new file mode 100644
index 0000000..078ac34
--- /dev/null
+++ b/src/third_party/mozjs-45/Makefile.in
@@ -0,0 +1,336 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ifeq (,$(MAKE_VERSION))
+$(error GNU Make is required)
+endif
+make_min_ver := 3.81
+ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
+$(error GNU Make $(make_min_ver) or higher is required)
+endif
+
+export TOPLEVEL_BUILD := 1
+
+default::
+
+ifdef MOZ_BUILD_APP
+include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
+endif
+
+include $(topsrcdir)/config/config.mk
+
+GARBAGE_DIRS += _javagen _profile staticlib
+DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
+   config/autoconf.mk \
+   mozilla-config.h \
+   netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
+   .mozconfig.mk
+
+ifdef JS_STANDALONE
+configure_dir = $(topsrcdir)/js/src
+else
+configure_dir = $(topsrcdir)
+endif
+
+ifndef TEST_MOZBUILD
+ifndef MOZ_PROFILE_USE
+# We need to explicitly put backend.RecursiveMakeBackend here
+# otherwise the rule in rules.mk doesn't run early enough.
+$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend
+ifndef JS_STANDALONE
+ifdef COMPILE_ENVIRONMENT
+$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
+endif
+endif
+endif
+endif
+
+ifdef JS_STANDALONE
+.PHONY: CLOBBER
+CLOBBER:
+else
+CLOBBER: $(topsrcdir)/CLOBBER
+	@echo 'STOP!  The CLOBBER file has changed.'
+	@echo 'Please run the build through a sanctioned build wrapper, such as'
+	@echo '"mach build" or client.mk.'
+	@exit 1
+endif
+
+$(topsrcdir)/configure: $(topsrcdir)/configure.in
+$(topsrcdir)/js/src/configure: $(topsrcdir)/js/src/configure.in
+$(topsrcdir)/configure $(topsrcdir)/js/src/configure:
+	@echo 'STOP!  $^ has changed, and your configure is out of date.'
+	@echo 'Please rerun autoconf and re-configure your build directory.'
+	@echo 'To ignore this message, touch "$@",'
+	@echo 'but your build might not succeed.'
+	@exit 1
+
+config.status: $(configure_dir)/configure
+js/src/config.status: $(topsrcdir)/js/src/configure
+config.status js/src/config.status:
+	@echo 'STOP!  $^ has changed and needs to be run again.'
+	@echo 'Please rerun it.'
+	@echo 'To ignore this message, touch "$(CURDIR)/$@",'
+	@echo 'but your build might not succeed.'
+	@exit 1
+
+# Regenerate the build backend if it is out of date. We only have this rule in
+# this main make file because having it in rules.mk and applied to partial tree
+# builds resulted in a world of hurt. Gory details are in bug 877308.
+#
+# The mach build driver will ensure the backend is up to date for partial tree
+# builds. This cleanly avoids most of the pain.
+
+ifndef TEST_MOZBUILD
+backend.RecursiveMakeBackend:
+	@echo 'Build configuration changed. Regenerating backend.'
+	$(PYTHON) config.status
+
+Makefile: backend.RecursiveMakeBackend
+	@$(TOUCH) $@
+
+include backend.RecursiveMakeBackend.pp
+
+default:: backend.RecursiveMakeBackend
+endif
+
+install_manifests := \
+  $(addprefix dist/,bin branding idl include public private sdk xpi-stage) \
+  _tests \
+  $(NULL)
+install_manifest_depends = \
+  CLOBBER \
+  $(configure_dir)/configure \
+  config.status \
+  backend.RecursiveMakeBackend \
+  $(NULL)
+
+ifndef JS_STANDALONE
+ifdef COMPILE_ENVIRONMENT
+install_manifest_depends += \
+  $(topsrcdir)/js/src/configure \
+  js/src/config.status \
+  $(NULL)
+endif
+endif
+
+.PHONY: install-manifests
+install-manifests: $(addprefix install-,$(install_manifests))
+
+# process_install_manifest needs to be invoked with --no-remove when building
+# js as standalone because automated builds are building nspr separately and
+# that would remove the resulting files.
+# Eventually, a standalone js build would just be able to build nspr itself,
+# removing the need for the former.
+ifdef JS_STANDALONE
+NO_REMOVE=1
+endif
+
+.PHONY: $(addprefix install-,$(install_manifests))
+$(addprefix install-,$(filter dist/%,$(install_manifests))): install-dist/%: $(install_manifest_depends)
+	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$*)
+
+# Dummy wrapper rule to allow the faster backend to piggy back
+install-dist_%: install-dist/% ;
+
+install-_tests: $(install_manifest_depends)
+	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/_tests)
+
+# For compatibility
+.PHONY: install-tests
+install-tests: install-_tests
+
+include $(topsrcdir)/build/moz-automation.mk
+
+# dist and _tests should be purged during cleaning. However, we don't want them
+# purged during PGO builds because they contain some auto-generated files.
+ifneq ($(filter-out maybe_clobber_profiledbuild,$(MAKECMDGOALS)),)
+GARBAGE_DIRS += dist _tests
+endif
+
+# Windows PGO builds don't perform a clean before the 2nd pass. So, we want
+# to preserve content for the 2nd pass on Windows. Everywhere else, we always
+# process the install manifests as part of export.
+# For the binaries rule, not all the install manifests matter, so force only
+# the interesting ones to be done.
+ifdef MOZ_PROFILE_USE
+ifndef NO_PROFILE_GUIDED_OPTIMIZE
+ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
+export:: install-manifests
+binaries::
+	@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
+endif
+endif
+else # !MOZ_PROFILE_USE (normal build)
+export:: install-manifests
+binaries::
+	@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
+endif
+
+# For historical reasons that are unknown, $(DIST)/sdk is always blown away
+# with no regard for PGO passes. This decision could probably be revisited.
+export:: install-dist/sdk
+
+ifndef JS_STANDALONE
+ifdef ENABLE_TESTS
+# Additional makefile targets to call automated test suites
+include $(topsrcdir)/testing/testsuite-targets.mk
+endif
+endif
+
+default all::
+	$(call BUILDSTATUS,TIERS $(TIERS) $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
+
+include $(topsrcdir)/config/rules.mk
+
+distclean::
+	$(RM) $(DIST_GARBAGE)
+
+ifeq ($(OS_ARCH),WINNT)
+# we want to copy PDB files on Windows
+MAKE_SYM_STORE_ARGS := -c --vcs-info
+ifdef PDBSTR_PATH
+MAKE_SYM_STORE_ARGS += -i
+endif
+DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
+# PDB files don't get moved to dist, so we need to scan the whole objdir
+MAKE_SYM_STORE_PATH := .
+endif
+ifeq ($(OS_ARCH),Darwin)
+# need to pass arch flags for universal builds
+ifdef UNIVERSAL_BINARY
+MAKE_SYM_STORE_ARGS := -c -a 'i386 x86_64' --vcs-info
+MAKE_SYM_STORE_PATH := $(DIST)/universal
+else
+MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
+MAKE_SYM_STORE_PATH := $(DIST)/bin
+endif
+DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
+endif
+ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
+MAKE_SYM_STORE_ARGS := -c --vcs-info
+DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
+MAKE_SYM_STORE_PATH := $(DIST)/bin
+endif
+MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
+
+SYM_STORE_SOURCE_DIRS := $(topsrcdir)
+
+ifndef JS_STANDALONE
+include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
+
+ifdef MOZ_SYMBOLS_EXTRA_BUILDID
+EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
+endif
+
+SYMBOL_INDEX_NAME = \
+  $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)$(EXTRA_BUILDID)-symbols.txt
+
+buildsymbols:
+ifdef MOZ_CRASHREPORTER
+	echo building symbol store
+	$(RM) -r $(DIST)/crashreporter-symbols
+	$(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
+	$(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+	$(NSINSTALL) -D $(DIST)/crashreporter-symbols
+	OBJCOPY='$(OBJCOPY)' \
+	$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
+	  $(MAKE_SYM_STORE_ARGS)                                          \
+	  $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir))               \
+	  $(DUMP_SYMS_BIN)                                                \
+	  $(DIST)/crashreporter-symbols                                   \
+	  $(MAKE_SYM_STORE_PATH) | grep -iv test >                        \
+	  $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
+	echo packing symbols
+	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
+	cd $(DIST)/crashreporter-symbols && \
+          zip -r9D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
+	cd $(DIST)/crashreporter-symbols && \
+	grep 'sym' $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
+	  mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
+	cd $(DIST)/crashreporter-symbols && \
+          zip -r9D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt'  -x '*test*' -x '*Test*'
+endif # MOZ_CRASHREPORTER
+
+uploadsymbols:
+ifdef MOZ_CRASHREPORTER
+ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
+	$(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+else
+	$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+endif
+endif
+
+# MOZ_SOURCE_STAMP is defined in package-name.mk with a deferred assignment.
+# exporting it makes make run its $(shell) command for each invoked submake,
+# so transform it to an immediate assignment.
+MOZ_SOURCE_STAMP := $(MOZ_SOURCE_STAMP)
+export MOZ_SOURCE_STAMP
+endif
+
+.PHONY: update-packaging
+update-packaging:
+	$(MAKE) -C tools/update-packaging
+
+.PHONY: pretty-package
+pretty-package:
+	unset MOZ_SIGN_CMD && $(MAKE) package MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-package-tests
+pretty-package-tests:
+	unset MOZ_SIGN_CMD && $(MAKE) package-tests MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-l10n-check
+pretty-l10n-check:
+	unset MOZ_SIGN_CMD && $(MAKE) l10n-check MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-update-packaging
+pretty-update-packaging:
+	unset MOZ_SIGN_CMD && $(MAKE) -C tools/update-packaging MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-installer
+pretty-installer:
+	unset MOZ_SIGN_CMD && $(MAKE) installer MOZ_PKG_PRETTYNAMES=1
+
+#XXX: this is a hack, since we don't want to clobber for MSVC
+# PGO support, but we can't do this test in client.mk
+ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
+# No point in clobbering if PGO has been explicitly disabled.
+ifndef NO_PROFILE_GUIDED_OPTIMIZE
+maybe_clobber_profiledbuild: clean
+else
+maybe_clobber_profiledbuild:
+endif
+else
+maybe_clobber_profiledbuild:
+	$(RM) $(DIST)/bin/*.pgc
+	find $(DIST)/$(MOZ_APP_NAME) -name '*.pgc' -exec mv {} $(DIST)/bin \;
+endif
+
+.PHONY: maybe_clobber_profiledbuild
+
+# Look for R_386_PC32 relocations in shared libs, these
+# break x86_64 builds and SELinux users.
+ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
+check::
+	@relcount=`find $(DIST)/bin -name '*.so' | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo 'FAILED: R_386_PC32 relocations detected in a shared library.  Did you use a system header without adding it to config/system-headers?'; exit 1; else echo 'PASSED'; fi
+endif
+
+ifdef JS_STANDALONE
+# Delegate js-specific rules to js
+check-%:
+	$(MAKE) -C js/src $@
+
+source-package install:
+	$(MAKE) -C js/src $@
+
+# Every export rule depends on config/export, but the rule for config/export
+# doesn't exist when building js non-standalone.
+.PHONY: config/export
+config/export:
+
+endif
+
+# There used to be build interdependencies here. They are now in config/recurse.mk
diff --git a/src/third_party/mozjs-45/README b/src/third_party/mozjs-45/README
new file mode 100644
index 0000000..5a7fff7
--- /dev/null
+++ b/src/third_party/mozjs-45/README
@@ -0,0 +1,8 @@
+This directory contains SpiderMonkey 45.
+
+This release is based on a revision of Mozilla 45:
+  http://hg.mozilla.org/releases/
+The changes in the patches/ directory were applied.
+
+MDN hosts the latest SpiderMonkey 45 release notes:
+  https://developer.mozilla.org/en-US/docs/SpiderMonkey/45
diff --git a/src/third_party/mozjs-45/build/.lldbinit.in b/src/third_party/mozjs-45/build/.lldbinit.in
new file mode 100644
index 0000000..425ca0f
--- /dev/null
+++ b/src/third_party/mozjs-45/build/.lldbinit.in
@@ -0,0 +1,2 @@
+#filter substitution
+script topsrcdir = "@topsrcdir@"; lldb.debugger.HandleCommand("command source -s true '%s'" % os.path.join(topsrcdir, ".lldbinit"))
diff --git a/src/third_party/mozjs-45/build/Makefile.in b/src/third_party/mozjs-45/build/Makefile.in
new file mode 100644
index 0000000..2d82093
--- /dev/null
+++ b/src/third_party/mozjs-45/build/Makefile.in
@@ -0,0 +1,100 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+USE_RCS_MK := 1
+include $(topsrcdir)/config/makefiles/makeutils.mk
+
+ifdef MOZ_APP_BASENAME
+APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
+
+MOZ_APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
+APP_INI_DEPS += $(DEPTH)/config/buildid
+
+DEFINES += -DMOZ_APP_BUILDID=$(MOZ_APP_BUILDID)
+
+APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
+
+MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template='{node}\n' 2>/dev/null))
+ifdef MOZ_SOURCE_STAMP
+DEFINES += -DMOZ_SOURCE_STAMP='$(MOZ_SOURCE_STAMP)'
+endif
+
+ifdef MOZ_INCLUDE_SOURCE_INFO
+source_repo ?= $(call getSourceRepo,$(topsrcdir)/$(MOZ_BUILD_APP)/..)
+ifneq (,$(source_repo))
+  DEFINES += -DMOZ_SOURCE_REPO='$(source_repo)'
+endif
+endif
+
+endif
+
+# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
+# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
+GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
+GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH))
+INSTALL_TARGETS += GDBINIT_OBJDIR
+
+# Put a .lldbinit in the bin directory and the objdir, to be picked up
+# automatically by LLDB when we debug executables using either of those two
+# directories as the current working directory.  The .lldbinit file will
+# load $(topsrcdir)/.lldbinit, which is where the actual debugging commands are.
+LLDBINIT_OBJDIR := .lldbinit.in
+LLDBINIT_OBJDIR_PATH = $(DEPTH)
+LLDBINIT_OBJDIR_FLAGS += -Dtopsrcdir=$(abspath $(topsrcdir))
+PP_TARGETS += LLDBINIT_OBJDIR
+
+LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
+LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
+INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
+
+# Put the .ycm_extra_conf.py file at the root of the objdir. It is used by
+# the vim plugin YouCompleteMe.
+YCM_FILES := $(topsrcdir)/.ycm_extra_conf.py
+YCM_DEST := $(abspath $(DEPTH))
+YCM_TARGET := export
+INSTALL_TARGETS += YCM
+
+ifdef MOZTTDIR
+# Install the Firefox OS fonts.
+include $(MOZTTDIR)/fonts.mk
+MOZTT_DEST = $(FINAL_TARGET)/fonts
+ifdef MOZ_B2GDROID
+MOZTT_DEST = $(FINAL_TARGET)/res/fonts
+endif
+MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
+INSTALL_TARGETS += MOZTT
+endif
+
+ifdef MOZ_VALGRIND
+_VALGRIND_DIR = $(DEPTH)/_valgrind
+GARBAGE_DIRS += $(_VALGRIND_DIR)
+
+_VALGRIND_FILES = \
+		$(topsrcdir)/build/valgrind/cross-architecture.sup \
+		$(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
+		$(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
+		$(NULL)
+_VALGRIND_DEST = $(_VALGRIND_DIR)
+INSTALL_TARGETS += _VALGRIND
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+TARGET_DEPTH = ..
+include $(srcdir)/automation-build.mk
+
+ifdef MOZ_APP_BASENAME
+$(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
+
+ifdef MOZ_APP_STATIC_INI
+application.ini.h: appini_header.py $(FINAL_TARGET)/application.ini
+	$(PYTHON) $^ > $@
+export:: application.ini.h
+GARBAGE += application.ini.h
+endif
+endif
+
+libs:: automation.py
+
diff --git a/src/third_party/mozjs-45/build/__init__.py b/src/third_party/mozjs-45/build/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/mozjs-45/build/__init__.py
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java
new file mode 100644
index 0000000..2477132
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+/**
+ * Object holding annotation data. Used by GeneratableElementIterator.
+ */
+public class AnnotationInfo {
+    public final String wrapperName;
+    public final boolean isMultithreaded;
+    public final boolean noThrow;
+    public final boolean narrowChars;
+    public final boolean catchException;
+
+    public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
+                          boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
+        wrapperName = aWrapperName;
+        isMultithreaded = aIsMultithreaded;
+        noThrow = aNoThrow;
+        narrowChars = aNarrowChars;
+        catchException = aCatchException;
+
+        if (noThrow && catchException) {
+            // It doesn't make sense to have these together
+            throw new IllegalArgumentException("noThrow and catchException are not allowed together");
+        }
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java
new file mode 100644
index 0000000..f852655
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java
@@ -0,0 +1,173 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class AnnotationProcessor {
+    public static final String SOURCE_FILE = "GeneratedJNIWrappers.cpp";
+    public static final String HEADER_FILE = "GeneratedJNIWrappers.h";
+    public static final String NATIVES_FILE = "GeneratedJNINatives.h";
+
+    public static final String GENERATED_COMMENT =
+            "// GENERATED CODE\n" +
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Java methods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
+
+    private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
+    private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
+    private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
+
+    public static void main(String[] args) {
+        // We expect a list of jars on the commandline. If missing, whinge about it.
+        if (args.length <= 1) {
+            System.err.println("Usage: java AnnotationProcessor jarfiles ...");
+            System.exit(1);
+        }
+
+        System.out.println("Processing annotations...");
+
+        // We want to produce the same output as last time as often as possible. Ordering of
+        // generated statements, therefore, needs to be consistent.
+        Arrays.sort(args);
+
+        // Start the clock!
+        long s = System.currentTimeMillis();
+
+        // Get an iterator over the classes in the jar files given...
+        Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
+
+        headerFile.append(
+                "#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" +
+                "#define " + getHeaderGuardName(HEADER_FILE) + "\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
+
+        implementationFile.append(
+                "#include \"GeneratedJNIWrappers.h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
+
+        nativesFile.append(
+                "#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" +
+                "#define " + getHeaderGuardName(NATIVES_FILE) + "\n" +
+                "\n" +
+                "#include \"GeneratedJNIWrappers.h\"\n" +
+                "#include \"mozilla/jni/Natives.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
+
+        while (jarClassIterator.hasNext()) {
+            generateClass(jarClassIterator.next());
+        }
+
+        implementationFile.append(
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
+
+        headerFile.append(
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
+
+        nativesFile.append(
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
+
+        writeOutputFile(SOURCE_FILE, implementationFile);
+        writeOutputFile(HEADER_FILE, headerFile);
+        writeOutputFile(NATIVES_FILE, nativesFile);
+
+        long e = System.currentTimeMillis();
+        System.out.println("Annotation processing complete in " + (e - s) + "ms");
+    }
+
+    private static void generateClass(final ClassWithOptions annotatedClass) {
+        // Get an iterator over the appropriately generated methods of this class
+        final GeneratableElementIterator methodIterator
+                = new GeneratableElementIterator(annotatedClass);
+        final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
+
+        if (!methodIterator.hasNext() && innerClasses.length == 0) {
+            return;
+        }
+
+        final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass);
+        generatorInstance.generateClasses(innerClasses);
+
+        // Iterate all annotated members in this class..
+        while (methodIterator.hasNext()) {
+            AnnotatableEntity aElementTuple = methodIterator.next();
+            switch (aElementTuple.mEntityType) {
+                case METHOD:
+                    generatorInstance.generateMethod(aElementTuple);
+                    break;
+                case NATIVE:
+                    generatorInstance.generateNative(aElementTuple);
+                    break;
+                case FIELD:
+                    generatorInstance.generateField(aElementTuple);
+                    break;
+                case CONSTRUCTOR:
+                    generatorInstance.generateConstructor(aElementTuple);
+                    break;
+            }
+        }
+
+        headerFile.append(generatorInstance.getHeaderFileContents());
+        implementationFile.append(generatorInstance.getWrapperFileContents());
+        nativesFile.append(generatorInstance.getNativesFileContents());
+
+        for (ClassWithOptions innerClass : innerClasses) {
+            generateClass(innerClass);
+        }
+    }
+
+    private static String getHeaderGuardName(final String name) {
+        return name.replaceAll("\\W", "_");
+    }
+
+    private static void writeOutputFile(final String name,
+                                        final StringBuilder content) {
+        FileOutputStream outStream = null;
+        try {
+            outStream = new FileOutputStream(name);
+            outStream.write(content.toString().getBytes());
+        } catch (IOException e) {
+            System.err.println("Unable to write " + name + ". Perhaps a permissions issue?");
+            e.printStackTrace(System.err);
+        } finally {
+            if (outStream != null) {
+                try {
+                    outStream.close();
+                } catch (IOException e) {
+                    System.err.println("Unable to close outStream due to "+e);
+                    e.printStackTrace(System.err);
+                }
+            }
+        }
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java b/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java
new file mode 100644
index 0000000..f96026e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java
@@ -0,0 +1,578 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.utils.Utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+
+public class CodeGenerator {
+    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+
+    // Buffers holding the strings to ultimately be written to the output files.
+    private final StringBuilder cpp = new StringBuilder();
+    private final StringBuilder header = new StringBuilder();
+    private final StringBuilder natives = new StringBuilder();
+    private final StringBuilder nativesInits = new StringBuilder();
+
+    private final Class<?> cls;
+    private final String clsName;
+
+    private final HashSet<String> takenMethodNames = new HashSet<String>();
+
+    public CodeGenerator(ClassWithOptions annotatedClass) {
+        this.cls = annotatedClass.wrappedClass;
+        this.clsName = annotatedClass.generatedName;
+
+        final String unqualifiedName = Utils.getUnqualifiedName(clsName);
+        header.append(
+                "class " + clsName + " : public mozilla::jni::Class<" + unqualifiedName + ">\n" +
+                "{\n" +
+                "public:\n" +
+                "    typedef mozilla::jni::Ref<" + unqualifiedName + "> Ref;\n" +
+                "    typedef mozilla::jni::LocalRef<" + unqualifiedName + "> LocalRef;\n" +
+                "    typedef mozilla::jni::GlobalRef<" + unqualifiedName + "> GlobalRef;\n" +
+                "    typedef const mozilla::jni::Param<" + unqualifiedName + ">& Param;\n" +
+                "\n" +
+                "    static constexpr char name[] =\n" +
+                "            \"" + cls.getName().replace('.', '/') + "\";\n" +
+                "\n" +
+                "protected:\n" +
+                "    " + unqualifiedName + "(jobject instance) : Class(instance) {}\n" +
+                "\n");
+
+        cpp.append(
+                "constexpr char " + clsName + "::name[];\n" +
+                "\n");
+
+        natives.append(
+                "template<class Impl>\n" +
+                "class " + clsName + "::Natives : " +
+                        "public mozilla::jni::NativeImpl<" + unqualifiedName + ", Impl>\n" +
+                "{\n");
+    }
+
+    private String getTraitsName(String uniqueName, boolean includeScope) {
+        return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
+    }
+
+    /**
+     * Return the C++ type name for this class or any class within the chain
+     * of declaring classes, if the target class matches the given type.
+     *
+     * Return null if the given type does not match any class searched.
+     */
+    private String getMatchingClassType(final Class<?> type) {
+        Class<?> cls = this.cls;
+        String clsName = this.clsName;
+
+        while (cls != null) {
+            if (type.equals(cls)) {
+                return clsName;
+            }
+            cls = cls.getDeclaringClass();
+            clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::")));
+        }
+        return null;
+    }
+
+    private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        final String clsName = getMatchingClassType(type);
+        if (clsName != null) {
+            return Utils.getUnqualifiedName(clsName) + "::Param";
+        }
+        return Utils.getNativeParameterType(type, info);
+    }
+
+    private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        final String clsName = getMatchingClassType(type);
+        if (clsName != null) {
+            return Utils.getUnqualifiedName(clsName) + "::LocalRef";
+        }
+        return Utils.getNativeReturnType(type, info);
+    }
+
+    private void generateMember(AnnotationInfo info, Member member,
+                                String uniqueName, Class<?> type, Class<?>[] argTypes) {
+        final StringBuilder args = new StringBuilder();
+        for (Class<?> argType : argTypes) {
+            args.append("\n                " + getNativeParameterType(argType, info) + ",");
+        }
+        if (args.length() > 0) {
+            args.setLength(args.length() - 1);
+        }
+
+        header.append(
+                "public:\n" +
+                "    struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
+                "        typedef " + Utils.getUnqualifiedName(clsName) + " Owner;\n" +
+                "        typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
+                "        typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
+                "        typedef mozilla::jni::Args<" + args + "> Args;\n" +
+                "        static constexpr char name[] = \"" +
+                        Utils.getMemberName(member) + "\";\n" +
+                "        static constexpr char signature[] =\n" +
+                "                \"" + Utils.getSignature(member) + "\";\n" +
+                "        static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
+                "        static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
+                "        static const mozilla::jni::ExceptionMode exceptionMode =\n" +
+                "                " + (
+                        info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
+                        info.noThrow ?        "mozilla::jni::ExceptionMode::IGNORE" :
+                                              "mozilla::jni::ExceptionMode::ABORT") + ";\n" +
+                "    };\n" +
+                "\n");
+
+        cpp.append(
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::name[];\n" +
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::signature[];\n" +
+                "\n");
+    }
+
+    private String getUniqueMethodName(String basename) {
+        String newName = basename;
+        int index = 1;
+
+        while (takenMethodNames.contains(newName)) {
+            newName = basename + (++index);
+        }
+
+        takenMethodNames.add(newName);
+        return newName;
+    }
+
+    /**
+     * Generate a method prototype that includes return and argument types,
+     * without specifiers (static, const, etc.).
+     */
+    private String generatePrototype(String name, Class<?>[] argTypes,
+                                     Class<?> returnType, AnnotationInfo info,
+                                     boolean includeScope, boolean includeArgName,
+                                     boolean isConst) {
+
+        final StringBuilder proto = new StringBuilder();
+        int argIndex = 0;
+
+        proto.append("auto ");
+
+        if (includeScope) {
+            proto.append(clsName).append("::");
+        }
+
+        proto.append(name).append('(');
+
+        for (Class<?> argType : argTypes) {
+            proto.append(getNativeParameterType(argType, info));
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (info.catchException && !returnType.equals(void.class)) {
+            proto.append(getNativeReturnType(returnType, info)).append('*');
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (proto.substring(proto.length() - 2).equals(", ")) {
+            proto.setLength(proto.length() - 2);
+        }
+
+        proto.append(')');
+
+        if (isConst) {
+            proto.append(" const");
+        }
+
+        if (info.catchException) {
+            proto.append(" -> nsresult");
+        } else {
+            proto.append(" -> ").append(getNativeReturnType(returnType, info));
+        }
+        return proto.toString();
+    }
+
+    /**
+     * Generate a method declaration that includes the prototype with specifiers,
+     * but without the method body.
+     */
+    private String generateDeclaration(String name, Class<?>[] argTypes,
+                                       Class<?> returnType, AnnotationInfo info,
+                                       boolean isStatic) {
+
+        return (isStatic ? "static " : "") +
+            generatePrototype(name, argTypes, returnType, info,
+                              /* includeScope */ false, /* includeArgName */ false,
+                              /* isConst */ !isStatic) + ';';
+    }
+
+    /**
+     * Generate a method definition that includes the prototype with specifiers,
+     * and with the method body.
+     */
+    private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
+                                      Class<?> returnType, AnnotationInfo info, boolean isStatic) {
+
+        final StringBuilder def = new StringBuilder(
+                generatePrototype(name, argTypes, returnType, info,
+                                  /* includeScope */ true, /* includeArgName */ true,
+                                  /* isConst */ !isStatic));
+        def.append("\n{\n");
+
+
+        // Generate code to handle the return value, if needed.
+        // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
+        // fewer instructions. We are guaranteed to set rv to the correct value later.
+
+        if (info.catchException && returnType.equals(void.class)) {
+            def.append(
+                    "    nsresult rv = NS_OK;\n" +
+                    "    ");
+
+        } else if (info.catchException) {
+            // Non-void return type
+            final String resultArg = "a" + argTypes.length;
+            def.append(
+                    "    MOZ_ASSERT(" + resultArg + ");\n" +
+                    "    nsresult rv = NS_OK;\n" +
+                    "    *" + resultArg + " = ");
+
+        } else {
+            def.append(
+                    "    return ");
+        }
+
+
+        // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
+
+        def.append(accessorName).append("(")
+           .append(isStatic ? "nullptr" : "this");
+
+        if (info.catchException) {
+            def.append(", &rv");
+        } else {
+            def.append(", nullptr");
+        }
+
+        // Generate the call argument list.
+        for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
+            def.append(", a").append(argIndex);
+        }
+
+        def.append(");\n");
+
+
+        if (info.catchException) {
+            def.append("    return rv;\n");
+        }
+
+        return def.append("}").toString();
+    }
+
+    /**
+     * Append the appropriate generated code to the buffers for the method provided.
+     *
+     * @param annotatedMethod The Java method, plus annotation data.
+     */
+    public void generateMethod(AnnotatableEntity annotatedMethod) {
+        // Unpack the tuple and extract some useful fields from the Method..
+        final Method method = annotatedMethod.getMethod();
+        final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+        final String uniqueName = getUniqueMethodName(info.wrapperName);
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final Class<?> returnType = method.getReturnType();
+
+        if (method.isSynthetic()) {
+            return;
+        }
+
+        generateMember(info, method, uniqueName, returnType, argTypes);
+
+        final boolean isStatic = Utils.isStatic(method);
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, argTypes,
+                                             returnType, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Method<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
+                "\n");
+    }
+
+    /**
+     * Append the appropriate generated code to the buffers for the native method provided.
+     *
+     * @param annotatedMethod The Java native method, plus annotation data.
+     */
+    public void generateNative(AnnotatableEntity annotatedMethod) {
+        // Unpack the tuple and extract some useful fields from the Method..
+        final Method method = annotatedMethod.getMethod();
+        final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+        final String uniqueName = getUniqueMethodName(info.wrapperName);
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final Class<?> returnType = method.getReturnType();
+
+        generateMember(info, method, uniqueName, returnType, argTypes);
+
+        final String traits = getTraitsName(uniqueName, /* includeScope */ true);
+
+        if (nativesInits.length() > 0) {
+            nativesInits.append(',');
+        }
+
+        nativesInits.append(
+                "\n" +
+                "\n" +
+                "        mozilla::jni::MakeNativeMethod<" + traits + ">(\n" +
+                "                mozilla::jni::NativeStub<" + traits + ", Impl>\n" +
+                "                ::template Wrap<&Impl::" + info.wrapperName + ">)");
+    }
+
+    private String getLiteral(Object val, AnnotationInfo info) {
+        final Class<?> type = val.getClass();
+
+        if (type.equals(char.class) || type.equals(Character.class)) {
+            final char c = (char) val;
+            if (c >= 0x20 && c < 0x7F) {
+                return "'" + c + '\'';
+            }
+            return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
+
+        } else if (type.equals(CharSequence.class) || type.equals(String.class)) {
+            final CharSequence str = (CharSequence) val;
+            final StringBuilder out = new StringBuilder(info.narrowChars ? "u8\"" : "u\"");
+            for (int i = 0; i < str.length(); i++) {
+                final char c = str.charAt(i);
+                if (c >= 0x20 && c < 0x7F) {
+                    out.append(c);
+                } else {
+                    out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
+                }
+            }
+            return out.append('"').toString();
+        }
+
+        return String.valueOf(val);
+    }
+
+    public void generateField(AnnotatableEntity annotatedField) {
+        final Field field = annotatedField.getField();
+        final AnnotationInfo info = annotatedField.mAnnotationInfo;
+        final String uniqueName = info.wrapperName;
+        final Class<?> type = field.getType();
+
+        // Handles a peculiar case when dealing with enum types. We don't care about this field.
+        // It just gets in the way and stops our code from compiling.
+        if (field.isSynthetic() || field.getName().equals("$VALUES")) {
+            return;
+        }
+
+        final boolean isStatic = Utils.isStatic(field);
+        final boolean isFinal = Utils.isFinal(field);
+
+        if (isStatic && isFinal && (type.isPrimitive() || type.equals(String.class))) {
+            Object val = null;
+            try {
+                field.setAccessible(true);
+                val = field.get(null);
+            } catch (final IllegalAccessException e) {
+            }
+
+            if (val != null && type.isPrimitive()) {
+                // For static final primitive fields, we can use a "static const" declaration.
+                header.append(
+                    "public:\n" +
+                    "    static const " + Utils.getNativeReturnType(type, info) +
+                            ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+
+            } else if (val != null && type.equals(String.class)) {
+                final String nativeType = info.narrowChars ? "char" : "char16_t";
+
+                header.append(
+                    "public:\n" +
+                    "    static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
+                    "\n");
+
+                cpp.append(
+                    "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
+                            "[] = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+            }
+
+            // Fall back to using accessors if we encounter an exception.
+        }
+
+        generateMember(info, field, uniqueName, type, EMPTY_CLASS_ARRAY);
+
+        final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, getterArgs,
+                                             type, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
+                        info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
+                "\n");
+
+        if (isFinal) {
+            return;
+        }
+
+        final Class<?>[] setterArgs = new Class<?>[] { type };
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, setterArgs,
+                                             void.class, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
+                        info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
+                "\n");
+    }
+
+    public void generateConstructor(AnnotatableEntity annotatedConstructor) {
+        // Unpack the tuple and extract some useful fields from the Method..
+        final Constructor<?> method = annotatedConstructor.getConstructor();
+        final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
+        final String wrapperName = "New";
+        final String uniqueName = getUniqueMethodName(wrapperName);
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final Class<?> returnType = cls;
+
+        if (method.isSynthetic()) {
+            return;
+        }
+
+        generateMember(info, method, uniqueName, returnType, argTypes);
+
+        header.append(
+                "    " + generateDeclaration(wrapperName, argTypes,
+                                             returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Constructor<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
+    }
+
+    public void generateMembers(Member[] members) {
+        for (Member m : members) {
+            if (!Modifier.isPublic(m.getModifiers())) {
+                continue;
+            }
+
+            String name = Utils.getMemberName(m);
+            name = name.substring(0, 1).toUpperCase() + name.substring(1);
+
+            final AnnotationInfo info = new AnnotationInfo(name,
+                    /* multithread */ true, /* nothrow */ false,
+                    /* narrow */ false, /* catchException */ true);
+            final AnnotatableEntity entity = new AnnotatableEntity(m, info);
+
+            if (m instanceof Constructor) {
+                generateConstructor(entity);
+            } else if (m instanceof Method) {
+                generateMethod(entity);
+            } else if (m instanceof Field) {
+                generateField(entity);
+            } else {
+                throw new IllegalArgumentException(
+                        "expected member to be Constructor, Method, or Field");
+            }
+        }
+    }
+
+    public void generateClasses(final ClassWithOptions[] classes) {
+        if (classes.length == 0) {
+            return;
+        }
+
+        header.append(
+                "public:\n");
+        for (final ClassWithOptions cls : classes) {
+            // Extract "Inner" from "Outer::Inner".
+            header.append(
+                    "    class " + Utils.getUnqualifiedName(cls.generatedName) + ";\n");
+        }
+        header.append('\n');
+    }
+
+    /**
+     * Get the finalised bytes to go into the generated wrappers file.
+     *
+     * @return The bytes to be written to the wrappers file.
+     */
+    public String getWrapperFileContents() {
+        return cpp.toString();
+    }
+
+    /**
+     * Get the finalised bytes to go into the generated header file.
+     *
+     * @return The bytes to be written to the header file.
+     */
+    public String getHeaderFileContents() {
+        if (nativesInits.length() > 0) {
+            header.append(
+                    "public:\n" +
+                    "    template<class Impl> class Natives;\n");
+        }
+        header.append(
+                "};\n" +
+                "\n");
+        return header.toString();
+    }
+
+    /**
+     * Get the finalised bytes to go into the generated natives header file.
+     *
+     * @return The bytes to be written to the header file.
+     */
+    public String getNativesFileContents() {
+        if (nativesInits.length() == 0) {
+            return "";
+        }
+        natives.append(
+                "public:\n" +
+                "    static constexpr JNINativeMethod methods[] = {" + nativesInits + '\n' +
+                "    };\n" +
+                "};\n" +
+                "\n" +
+                "template<class Impl>\n" +
+                "constexpr JNINativeMethod " + clsName + "::Natives<Impl>::methods[];\n" +
+                "\n");
+        return natives.toString();
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in b/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in
new file mode 100644
index 0000000..55b455e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in
@@ -0,0 +1,10 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+include $(topsrcdir)/config/rules.mk
+
+# Include Android specific java flags, instead of what's in rules.mk.
+include $(topsrcdir)/config/android-common.mk
+
+export:: annotationProcessors.jar
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java b/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java
new file mode 100644
index 0000000..8b045fa
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java
@@ -0,0 +1,258 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import com.android.tools.lint.checks.ApiLookup;
+import com.android.tools.lint.LintCliClient;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+import org.mozilla.gecko.annotationProcessors.utils.Utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Scanner;
+import java.util.Vector;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class SDKProcessor {
+    public static final String GENERATED_COMMENT =
+            "// GENERATED CODE\n" +
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
+
+    private static ApiLookup sApiLookup;
+    private static int sMaxSdkVersion;
+
+    public static void main(String[] args) throws Exception {
+        // We expect a list of jars on the commandline. If missing, whinge about it.
+        if (args.length < 5) {
+            System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
+            System.exit(1);
+        }
+
+        System.out.println("Processing platform bindings...");
+
+        String sdkJar = args[0];
+        Vector classes = getClassList(args[1]);
+        String outdir = args[2];
+        String generatedFilePrefix = args[3];
+        sMaxSdkVersion = Integer.parseInt(args[4]);
+
+        LintCliClient lintClient = new LintCliClient();
+        sApiLookup = ApiLookup.get(lintClient);
+
+        // Start the clock!
+        long s = System.currentTimeMillis();
+
+        // Get an iterator over the classes in the jar files given...
+        // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
+
+        StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
+        headerFile.append(
+                "#ifndef " + generatedFilePrefix + "_h__\n" +
+                "#define " + generatedFilePrefix + "_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
+
+        StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
+        implementationFile.append(
+                "#include \"" + generatedFilePrefix + ".h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
+
+        // Used to track the calls to the various class-specific initialisation functions.
+        ClassLoader loader = null;
+        try {
+            loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
+                                                SDKProcessor.class.getClassLoader());
+        } catch (Exception e) {
+            throw new RuntimeException(e.toString());
+        }
+
+        for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
+            String className = i.next();
+            System.out.println("Looking up: " + className);
+
+            generateClass(Class.forName(className, true, loader),
+                          implementationFile,
+                          headerFile);
+        }
+
+        implementationFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
+
+        headerFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif\n");
+
+        writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
+        long e = System.currentTimeMillis();
+        System.out.println("SDK processing complete in " + (e - s) + "ms");
+    }
+
+    private static int getAPIVersion(Class<?> cls, Member m) {
+        if (m instanceof Method || m instanceof Constructor) {
+            return sApiLookup.getCallVersion(
+                    cls.getName().replace('.', '/'),
+                    Utils.getMemberName(m),
+                    Utils.getSignature(m));
+        } else if (m instanceof Field) {
+            return sApiLookup.getFieldVersion(
+                    Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
+        } else {
+            throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
+        }
+    }
+
+    private static Member[] sortAndFilterMembers(Class<?> cls, Member[] members) {
+        Arrays.sort(members, new Comparator<Member>() {
+            @Override
+            public int compare(Member a, Member b) {
+                return a.getName().compareTo(b.getName());
+            }
+        });
+
+        ArrayList<Member> list = new ArrayList<>();
+        for (Member m : members) {
+            // Sometimes (e.g. Bundle) has methods that moved to/from a superclass in a later SDK
+            // version, so we check for both classes and see if we can find a minimum SDK version.
+            int version = getAPIVersion(cls, m);
+            final int version2 = getAPIVersion(m.getDeclaringClass(), m);
+            if (version2 > 0 && version2 < version) {
+                version = version2;
+            }
+            if (version > sMaxSdkVersion) {
+                System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
+                    ", version " + version + " > " + sMaxSdkVersion);
+                continue;
+            }
+
+            // Sometimes (e.g. KeyEvent) a field can appear in both a class and a superclass. In
+            // that case we want to filter out the version that appears in the superclass, or
+            // we'll have bindings with duplicate names.
+            try {
+                if (m instanceof Field && !m.equals(cls.getField(m.getName()))) {
+                    // m is a field in a superclass that has been hidden by
+                    // a field with the same name in a subclass.
+                    System.out.println("Skipping " + m.getName() +
+                                       " from " + m.getDeclaringClass());
+                    continue;
+                }
+            } catch (final NoSuchFieldException e) {
+            }
+
+            list.add(m);
+        }
+
+        return list.toArray(new Member[list.size()]);
+    }
+
+    private static void generateClass(Class<?> clazz,
+                                      StringBuilder implementationFile,
+                                      StringBuilder headerFile) {
+        String generatedName = clazz.getSimpleName();
+
+        CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
+
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getConstructors()));
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getMethods()));
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getFields()));
+
+        headerFile.append(generator.getHeaderFileContents());
+        implementationFile.append(generator.getWrapperFileContents());
+    }
+
+    private static Vector<String> getClassList(String path) {
+        Scanner scanner = null;
+        try {
+            scanner = new Scanner(new FileInputStream(path));
+
+            Vector lines = new Vector();
+            while (scanner.hasNextLine()) {
+                lines.add(scanner.nextLine());
+            }
+            return lines;
+        } catch (Exception e) {
+            System.out.println(e.toString());
+            return null;
+        } finally {
+            if (scanner != null) {
+                scanner.close();
+            }
+        }
+    }
+
+    private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile,
+                                         StringBuilder aImplementationFile) {
+        FileOutputStream implStream = null;
+        try {
+            implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp"));
+            implStream.write(aImplementationFile.toString().getBytes());
+        } catch (IOException e) {
+            System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
+            e.printStackTrace(System.err);
+        } finally {
+            if (implStream != null) {
+                try {
+                    implStream.close();
+                } catch (IOException e) {
+                    System.err.println("Unable to close implStream due to "+e);
+                    e.printStackTrace(System.err);
+                }
+            }
+        }
+
+        FileOutputStream headerStream = null;
+        try {
+            headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h"));
+            headerStream.write(aHeaderFile.toString().getBytes());
+        } catch (IOException e) {
+            System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
+            e.printStackTrace(System.err);
+        } finally {
+            if (headerStream != null) {
+                try {
+                    headerStream.close();
+                } catch (IOException e) {
+                    System.err.println("Unable to close headerStream due to "+e);
+                    e.printStackTrace(System.err);
+                }
+            }
+        }
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java
new file mode 100644
index 0000000..b11a6c4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Union type to hold either a method, field, or ctor. Allows us to iterate "The generatable stuff", despite
+ * the fact that such things can be of either flavour.
+ */
+public class AnnotatableEntity {
+    public enum ENTITY_TYPE {METHOD, NATIVE, FIELD, CONSTRUCTOR}
+
+    private final Member mMember;
+    public final ENTITY_TYPE mEntityType;
+
+    public final AnnotationInfo mAnnotationInfo;
+
+    public AnnotatableEntity(Member aObject, AnnotationInfo aAnnotationInfo) {
+        mMember = aObject;
+        mAnnotationInfo = aAnnotationInfo;
+
+        if (aObject instanceof Method) {
+            if (Modifier.isNative(aObject.getModifiers())) {
+                mEntityType = ENTITY_TYPE.NATIVE;
+            } else {
+                mEntityType = ENTITY_TYPE.METHOD;
+            }
+        } else if (aObject instanceof Field) {
+            mEntityType = ENTITY_TYPE.FIELD;
+        } else {
+            mEntityType = ENTITY_TYPE.CONSTRUCTOR;
+        }
+    }
+
+    public Method getMethod() {
+        if (mEntityType != ENTITY_TYPE.METHOD && mEntityType != ENTITY_TYPE.NATIVE) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Method) mMember;
+    }
+    public Field getField() {
+        if (mEntityType != ENTITY_TYPE.FIELD) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Field) mMember;
+    }
+    public Constructor<?> getConstructor() {
+        if (mEntityType != ENTITY_TYPE.CONSTRUCTOR) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Constructor<?>) mMember;
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java
new file mode 100644
index 0000000..070cff8
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+public class ClassWithOptions {
+    public final Class<?> wrappedClass;
+    public final String generatedName;
+
+    public ClassWithOptions(Class<?> someClass, String name) {
+        wrappedClass = someClass;
+        generatedName = name;
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
new file mode 100644
index 0000000..7e74399
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * A classloader which can be initialised with a list of jar files and which can provide an iterator
+ * over the top level classes in the jar files it was initialised with.
+ * classNames is kept sorted to ensure iteration order is consistent across program invocations.
+ * Otherwise, we'd forever be reporting the outdatedness of the generated code as we permute its
+ * contents.
+ */
+public class IterableJarLoadingURLClassLoader extends URLClassLoader {
+    LinkedList<String> classNames = new LinkedList<String>();
+
+    /**
+     * Create an instance and return its iterator. Provides an iterator over the classes in the jar
+     * files provided as arguments.
+     * Inner classes are not supported.
+     *
+     * @param args A list of jar file names an iterator over the classes of which is desired.
+     * @return An iterator over the top level classes in the jar files provided, in arbitrary order.
+     */
+    public static Iterator<ClassWithOptions> getIteratorOverJars(String[] args) {
+        URL[] urlArray = new URL[args.length];
+        LinkedList<String> aClassNames = new LinkedList<String>();
+
+        for (int i = 0; i < args.length; i++) {
+            try {
+                urlArray[i] = (new File(args[i])).toURI().toURL();
+
+                Enumeration<JarEntry> entries = new JarFile(args[i]).entries();
+                while (entries.hasMoreElements()) {
+                    JarEntry e = entries.nextElement();
+                    String fName = e.getName();
+                    if (!fName.endsWith(".class")) {
+                        continue;
+                    }
+                    final String className = fName.substring(0, fName.length() - 6).replace('/', '.');
+
+                    aClassNames.add(className);
+                }
+            } catch (IOException e) {
+                System.err.println("Error loading jar file \"" + args[i] + '"');
+                e.printStackTrace(System.err);
+            }
+        }
+        Collections.sort(aClassNames);
+        return new JarClassIterator(new IterableJarLoadingURLClassLoader(urlArray, aClassNames));
+    }
+
+    /**
+     * Constructs a classloader capable of loading all classes given as URLs in urls. Used by static
+     * method above.
+     *
+     * @param urls        URLs for all classes the new instance shall be capable of loading.
+     * @param aClassNames A list of names of the classes this instance shall be capable of loading.
+     */
+    protected IterableJarLoadingURLClassLoader(URL[] urls, LinkedList<String> aClassNames) {// Array to populate with URLs for each class in the given jars.
+        super(urls);
+        classNames = aClassNames;
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java
new file mode 100644
index 0000000..452de81
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import java.util.Iterator;
+
+/**
+ * Class for iterating over an IterableJarLoadingURLClassLoader's classes.
+ *
+ * This class is not thread safe: use it only from a single thread.
+ */
+public class JarClassIterator implements Iterator<ClassWithOptions> {
+    private IterableJarLoadingURLClassLoader mTarget;
+    private Iterator<String> mTargetClassListIterator;
+
+    private ClassWithOptions lookAhead;
+
+    public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) {
+        mTarget = aTarget;
+        mTargetClassListIterator = aTarget.classNames.iterator();
+    }
+
+    @Override
+    public boolean hasNext() {
+        return fillLookAheadIfPossible();
+    }
+
+    @Override
+    public ClassWithOptions next() {
+        if (!fillLookAheadIfPossible()) {
+            throw new IllegalStateException("Failed to look ahead in next()!");
+        }
+        ClassWithOptions next = lookAhead;
+        lookAhead = null;
+        return next;
+    }
+
+    private boolean fillLookAheadIfPossible() {
+        if (lookAhead != null) {
+            return true;
+        }
+
+        if (!mTargetClassListIterator.hasNext()) {
+            return false;
+        }
+
+        String className = mTargetClassListIterator.next();
+        try {
+            Class<?> ret = mTarget.loadClass(className);
+
+            // Incremental builds can leave stale classfiles in the jar. Such classfiles will cause
+            // an exception at this point. We can safely ignore these classes - they cannot possibly
+            // ever be loaded as they conflict with their parent class and will be killed by
+            // Proguard later on anyway.
+            final Class<?> enclosingClass;
+            try {
+                enclosingClass = ret.getEnclosingClass();
+            } catch (IncompatibleClassChangeError e) {
+                return fillLookAheadIfPossible();
+            }
+
+            if (enclosingClass != null) {
+                // Anonymous inner class - unsupported.
+                // Or named inner class, which will be processed when we process the outer class.
+                return fillLookAheadIfPossible();
+            }
+
+            lookAhead = new ClassWithOptions(ret, ret.getSimpleName());
+            return true;
+        } catch (ClassNotFoundException e) {
+            System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
+            e.printStackTrace();
+            System.exit(2);
+        }
+        return false;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Removal of classes from iterator not supported.");
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/moz.build b/src/third_party/mozjs-45/build/annotationProcessors/moz.build
new file mode 100644
index 0000000..f2200eb
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+jar = add_java_jar('annotationProcessors')
+jar.sources += [
+    'AnnotationInfo.java',
+    'AnnotationProcessor.java',
+    'classloader/AnnotatableEntity.java',
+    'classloader/ClassWithOptions.java',
+    'classloader/IterableJarLoadingURLClassLoader.java',
+    'classloader/JarClassIterator.java',
+    'CodeGenerator.java',
+    'SDKProcessor.java',
+    'utils/AlphabeticAnnotatableEntityComparator.java',
+    'utils/GeneratableElementIterator.java',
+    'utils/Utils.java',
+]
+jar.extra_jars += [
+    CONFIG['ANDROID_TOOLS'] + '/lib/lint.jar',
+    CONFIG['ANDROID_TOOLS'] + '/lib/lint-checks.jar',
+]
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
new file mode 100644
index 0000000..2ee2ae5
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.Comparator;
+
+public class AlphabeticAnnotatableEntityComparator<T extends Member> implements Comparator<T> {
+    @Override
+    public int compare(T aLhs, T aRhs) {
+        // Constructors, Methods, Fields.
+        boolean lIsConstructor = aLhs instanceof Constructor;
+        boolean rIsConstructor = aRhs instanceof Constructor;
+        boolean lIsMethod = aLhs instanceof Method;
+        boolean rIsField = aRhs instanceof Field;
+
+        if (lIsConstructor) {
+            if (!rIsConstructor) {
+                return -1;
+            }
+        } else if (lIsMethod) {
+            if (rIsConstructor) {
+                return 1;
+            } else if (rIsField) {
+                return -1;
+            }
+        } else {
+            if (!rIsField) {
+                return 1;
+            }
+        }
+
+        // Verify these objects are the same type and cast them.
+        if (aLhs instanceof Method) {
+            return compare((Method) aLhs, (Method) aRhs);
+        } else if (aLhs instanceof Field) {
+            return compare((Field) aLhs, (Field) aRhs);
+        } else {
+            return compare((Constructor) aLhs, (Constructor) aRhs);
+        }
+    }
+
+    // Alas, the type system fails us.
+    private static int compare(Method aLhs, Method aRhs) {
+        // Initially, attempt to differentiate the methods be name alone..
+        String lName = aLhs.getName();
+        String rName = aRhs.getName();
+
+        int ret = lName.compareTo(rName);
+        if (ret != 0) {
+            return ret;
+        }
+
+        // The names were the same, so we need to compare signatures to find their uniqueness..
+        lName = Utils.getSignature(aLhs);
+        rName = Utils.getSignature(aRhs);
+
+        return lName.compareTo(rName);
+    }
+
+    private static int compare(Constructor<?> aLhs, Constructor<?> aRhs) {
+        // The names will be the same, so we need to compare signatures to find their uniqueness..
+        String lName = Utils.getSignature(aLhs);
+        String rName = Utils.getSignature(aRhs);
+
+        return lName.compareTo(rName);
+    }
+
+    private static int compare(Field aLhs, Field aRhs) {
+        // Compare field names..
+        String lName = aLhs.getName();
+        String rName = aRhs.getName();
+
+        return lName.compareTo(rName);
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java
new file mode 100644
index 0000000..4f27f2d
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -0,0 +1,220 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+
+/**
+ * Iterator over the methods in a given method list which have the WrappedJNIMethod
+ * annotation. Returns an object containing both the annotation (Which may contain interesting
+ * parameters) and the argument.
+ */
+public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
+    private final ClassWithOptions mClass;
+    private final Member[] mObjects;
+    private AnnotatableEntity mNextReturnValue;
+    private int mElementIndex;
+
+    private boolean mIterateEveryEntry;
+
+    public GeneratableElementIterator(ClassWithOptions annotatedClass) {
+        mClass = annotatedClass;
+
+        final Class<?> aClass = annotatedClass.wrappedClass;
+        // Get all the elements of this class as AccessibleObjects.
+        Member[] aMethods = aClass.getDeclaredMethods();
+        Member[] aFields = aClass.getDeclaredFields();
+        Member[] aCtors = aClass.getDeclaredConstructors();
+
+        // Shove them all into one buffer.
+        Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length];
+
+        int offset = 0;
+        System.arraycopy(aMethods, 0, objs, 0, aMethods.length);
+        offset += aMethods.length;
+        System.arraycopy(aFields, 0, objs, offset, aFields.length);
+        offset += aFields.length;
+        System.arraycopy(aCtors, 0, objs, offset, aCtors.length);
+
+        // Sort the elements to ensure determinism.
+        Arrays.sort(objs, new AlphabeticAnnotatableEntityComparator<Member>());
+        mObjects = objs;
+
+        // Check for "Wrap ALL the things" flag.
+        for (Annotation annotation : aClass.getDeclaredAnnotations()) {
+            final String annotationTypeName = annotation.annotationType().getName();
+            if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
+                mIterateEveryEntry = true;
+                break;
+            }
+        }
+
+        findNextValue();
+    }
+
+    private Class<?>[] getFilteredInnerClasses() {
+        // Go through all inner classes and see which ones we want to generate.
+        final Class<?>[] candidates = mClass.wrappedClass.getDeclaredClasses();
+        int count = 0;
+
+        for (int i = 0; i < candidates.length; ++i) {
+            final GeneratableElementIterator testIterator
+                    = new GeneratableElementIterator(new ClassWithOptions(candidates[i], null));
+            if (testIterator.hasNext()
+                    || testIterator.getFilteredInnerClasses() != null) {
+                count++;
+                continue;
+            }
+            // Clear out ones that don't match.
+            candidates[i] = null;
+        }
+        return count > 0 ? candidates : null;
+    }
+
+    public ClassWithOptions[] getInnerClasses() {
+        final Class<?>[] candidates = getFilteredInnerClasses();
+        if (candidates == null) {
+            return new ClassWithOptions[0];
+        }
+
+        int count = 0;
+        for (Class<?> candidate : candidates) {
+            if (candidate != null) {
+                count++;
+            }
+        }
+
+        final ClassWithOptions[] ret = new ClassWithOptions[count];
+        count = 0;
+        for (Class<?> candidate : candidates) {
+            if (candidate != null) {
+                ret[count++] = new ClassWithOptions(
+                        candidate, mClass.generatedName + "::" + candidate.getSimpleName());
+            }
+        }
+        assert ret.length == count;
+
+        Arrays.sort(ret, new Comparator<ClassWithOptions>() {
+            @Override public int compare(ClassWithOptions lhs, ClassWithOptions rhs) {
+                return lhs.generatedName.compareTo(rhs.generatedName);
+            }
+        });
+        return ret;
+    }
+
+    /**
+     * Find and cache the next appropriately annotated method, plus the annotation parameter, if
+     * one exists. Otherwise cache null, so hasNext returns false.
+     */
+    private void findNextValue() {
+        while (mElementIndex < mObjects.length) {
+            Member candidateElement = mObjects[mElementIndex];
+            mElementIndex++;
+            for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
+                // WrappedJNIMethod has parameters. Use Reflection to obtain them.
+                Class<? extends Annotation> annotationType = annotation.annotationType();
+                final String annotationTypeName = annotationType.getName();
+                if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
+                    String stubName = null;
+                    boolean isMultithreadedStub = false;
+                    boolean noThrow = false;
+                    boolean narrowChars = false;
+                    boolean catchException = false;
+                    try {
+                        // Determine the explicitly-given name of the stub to generate, if any.
+                        final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
+                        stubNameMethod.setAccessible(true);
+                        stubName = (String) stubNameMethod.invoke(annotation);
+
+                        // Determine if the generated stub is to allow calls from multiple threads.
+                        final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
+                        multithreadedStubMethod.setAccessible(true);
+                        isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
+
+                        // Determine if ignoring exceptions
+                        final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
+                        noThrowMethod.setAccessible(true);
+                        noThrow = (Boolean) noThrowMethod.invoke(annotation);
+
+                        // Determine if strings should be wide or narrow
+                        final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
+                        narrowCharsMethod.setAccessible(true);
+                        narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
+
+                        // Determine if we should catch exceptions
+                        final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
+                        catchExceptionMethod.setAccessible(true);
+                        catchException = (Boolean) catchExceptionMethod.invoke(annotation);
+
+                    } catch (NoSuchMethodException e) {
+                        System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
+                        e.printStackTrace(System.err);
+                        System.exit(3);
+                    } catch (IllegalAccessException e) {
+                        System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
+                        e.printStackTrace(System.err);
+                        System.exit(4);
+                    } catch (InvocationTargetException e) {
+                        System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
+                        e.printStackTrace(System.err);
+                        System.exit(5);
+                    }
+
+                    // If the method name was not explicitly given in the annotation generate one...
+                    if (stubName.isEmpty()) {
+                        stubName = Utils.getNativeName(candidateElement);
+                    }
+
+                    AnnotationInfo annotationInfo = new AnnotationInfo(
+                        stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
+                    mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
+                    return;
+                }
+            }
+
+            // If no annotation found, we might be expected to generate anyway
+            // using default arguments, thanks to the "Generate everything" annotation.
+            if (mIterateEveryEntry) {
+                AnnotationInfo annotationInfo = new AnnotationInfo(
+                    Utils.getNativeName(candidateElement),
+                    /* multithreaded */ true,
+                    /* noThrow */ false,
+                    /* narrowChars */ false,
+                    /* catchException */ false);
+                mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
+                return;
+            }
+        }
+        mNextReturnValue = null;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return mNextReturnValue != null;
+    }
+
+    @Override
+    public AnnotatableEntity next() {
+        AnnotatableEntity ret = mNextReturnValue;
+        findNextValue();
+        return ret;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Removal of methods from GeneratableElementIterator not supported.");
+    }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java
new file mode 100644
index 0000000..0e96f72
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java
@@ -0,0 +1,251 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+/**
+ * A collection of utility methods used by CodeGenerator. Largely used for translating types.
+ */
+public class Utils {
+
+    // A collection of lookup tables to simplify the functions to follow...
+    private static final HashMap<String, String> NATIVE_TYPES = new HashMap<String, String>();
+
+    static {
+        NATIVE_TYPES.put("void", "void");
+        NATIVE_TYPES.put("boolean", "bool");
+        NATIVE_TYPES.put("byte", "int8_t");
+        NATIVE_TYPES.put("char", "char16_t");
+        NATIVE_TYPES.put("short", "int16_t");
+        NATIVE_TYPES.put("int", "int32_t");
+        NATIVE_TYPES.put("long", "int64_t");
+        NATIVE_TYPES.put("float", "float");
+        NATIVE_TYPES.put("double", "double");
+    }
+
+    private static final HashMap<String, String> NATIVE_ARRAY_TYPES = new HashMap<String, String>();
+
+    static {
+        NATIVE_ARRAY_TYPES.put("boolean", "mozilla::jni::BooleanArray");
+        NATIVE_ARRAY_TYPES.put("byte", "mozilla::jni::ByteArray");
+        NATIVE_ARRAY_TYPES.put("char", "mozilla::jni::CharArray");
+        NATIVE_ARRAY_TYPES.put("short", "mozilla::jni::ShortArray");
+        NATIVE_ARRAY_TYPES.put("int", "mozilla::jni::IntArray");
+        NATIVE_ARRAY_TYPES.put("long", "mozilla::jni::LongArray");
+        NATIVE_ARRAY_TYPES.put("float", "mozilla::jni::FloatArray");
+        NATIVE_ARRAY_TYPES.put("double", "mozilla::jni::DoubleArray");
+    }
+
+    private static final HashMap<String, String> CLASS_DESCRIPTORS = new HashMap<String, String>();
+
+    static {
+        CLASS_DESCRIPTORS.put("void", "V");
+        CLASS_DESCRIPTORS.put("boolean", "Z");
+        CLASS_DESCRIPTORS.put("byte", "B");
+        CLASS_DESCRIPTORS.put("char", "C");
+        CLASS_DESCRIPTORS.put("short", "S");
+        CLASS_DESCRIPTORS.put("int", "I");
+        CLASS_DESCRIPTORS.put("long", "J");
+        CLASS_DESCRIPTORS.put("float", "F");
+        CLASS_DESCRIPTORS.put("double", "D");
+    }
+
+    /**
+     * Get the C++ type corresponding to the provided type parameter.
+     *
+     * @param type Class to determine the corresponding JNI type for.
+     * @return C++ type as a String
+     */
+    public static String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
+
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
+        }
+
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::Param";
+            }
+            return "mozilla::jni::ObjectArray::Param";
+        }
+
+        if (type.equals(String.class) || type.equals(CharSequence.class)) {
+            return "mozilla::jni::String::Param";
+        }
+
+        if (type.equals(Class.class)) {
+            // You're doing reflection on Java objects from inside C, returning Class objects
+            // to C, generating the corresponding code using this Java program. Really?!
+            return "mozilla::jni::ClassObject::Param";
+        }
+
+        if (type.equals(Throwable.class)) {
+            return "mozilla::jni::Throwable::Param";
+        }
+
+        return "mozilla::jni::Object::Param";
+    }
+
+    public static String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
+
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
+        }
+
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::LocalRef";
+            }
+            return "mozilla::jni::ObjectArray::LocalRef";
+        }
+
+        if (type.equals(String.class)) {
+            return "mozilla::jni::String::LocalRef";
+        }
+
+        if (type.equals(Class.class)) {
+            // You're doing reflection on Java objects from inside C, returning Class objects
+            // to C, generating the corresponding code using this Java program. Really?!
+            return "mozilla::jni::ClassObject::LocalRef";
+        }
+
+        if (type.equals(Throwable.class)) {
+            return "mozilla::jni::Throwable::LocalRef";
+        }
+
+        return "mozilla::jni::Object::LocalRef";
+    }
+
+    /**
+     * Get the JNI class descriptor corresponding to the provided type parameter.
+     *
+     * @param type Class to determine the corresponding JNI descriptor for.
+     * @return Class descripor as a String
+     */
+    public static String getClassDescriptor(Class<?> type) {
+        final String name = type.getName().replace('.', '/');
+
+        if (CLASS_DESCRIPTORS.containsKey(name)) {
+            return CLASS_DESCRIPTORS.get(name);
+        }
+
+        if (type.isArray()) {
+            // Array names are already in class descriptor form.
+            return name;
+        }
+
+        return "L" + name + ';';
+    }
+
+    /**
+     * Get the JNI signaure for a member.
+     *
+     * @param member Member to get the signature for.
+     * @return JNI signature as a string
+     */
+    public static String getSignature(Member member) {
+        return member instanceof Field ?  getSignature((Field) member) :
+               member instanceof Method ? getSignature((Method) member) :
+                                          getSignature((Constructor<?>) member);
+    }
+
+    /**
+     * Get the JNI signaure for a field.
+     *
+     * @param member Field to get the signature for.
+     * @return JNI signature as a string
+     */
+    public static String getSignature(Field member) {
+        return getClassDescriptor(member.getType());
+    }
+
+    private static String getSignature(Class<?>[] args, Class<?> ret) {
+        final StringBuilder sig = new StringBuilder("(");
+        for (int i = 0; i < args.length; i++) {
+            sig.append(getClassDescriptor(args[i]));
+        }
+        return sig.append(')').append(getClassDescriptor(ret)).toString();
+    }
+
+    /**
+     * Get the JNI signaure for a method.
+     *
+     * @param member Method to get the signature for.
+     * @return JNI signature as a string
+     */
+    public static String getSignature(Method member) {
+        return getSignature(member.getParameterTypes(), member.getReturnType());
+    }
+
+    /**
+     * Get the JNI signaure for a constructor.
+     *
+     * @param member Constructor to get the signature for.
+     * @return JNI signature as a string
+     */
+    public static String getSignature(Constructor<?> member) {
+        return getSignature(member.getParameterTypes(), void.class);
+    }
+
+    /**
+     * Get the C++ name for a member.
+     *
+     * @param member Member to get the name for.
+     * @return JNI name as a string
+     */
+    public static String getNativeName(Member member) {
+        final String name = getMemberName(member);
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
+    }
+
+    /**
+     * Get the JNI name for a member.
+     *
+     * @param member Member to get the name for.
+     * @return JNI name as a string
+     */
+    public static String getMemberName(Member member) {
+        if (member instanceof Constructor) {
+            return "<init>";
+        }
+        return member.getName();
+    }
+
+    public static String getUnqualifiedName(String name) {
+        return name.substring(name.lastIndexOf(':') + 1);
+    }
+
+    /**
+     * Determine if a member is declared static.
+     *
+     * @param member The Member to check.
+     * @return true if the member is declared static, false otherwise.
+     */
+    public static boolean isStatic(final Member member) {
+        return Modifier.isStatic(member.getModifiers());
+    }
+
+    /**
+     * Determine if a member is declared final.
+     *
+     * @param member The Member to check.
+     * @return true if the member is declared final, false otherwise.
+     */
+    public static boolean isFinal(final Member member) {
+        return Modifier.isFinal(member.getModifiers());
+    }
+}
diff --git a/src/third_party/mozjs-45/build/appini_header.py b/src/third_party/mozjs-45/build/appini_header.py
new file mode 100644
index 0000000..d637d5e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/appini_header.py
@@ -0,0 +1,60 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+'''Parses a given application.ini file and outputs the corresponding
+   XULAppData structure as a C++ header file'''
+
+import ConfigParser
+import sys
+
+def main(file):
+    config = ConfigParser.RawConfigParser()
+    config.read(file)
+    flags = set()
+    try:
+        if config.getint('XRE', 'EnableProfileMigrator') == 1:
+            flags.add('NS_XRE_ENABLE_PROFILE_MIGRATOR')
+    except: pass
+    try:
+        if config.getint('Crash Reporter', 'Enabled') == 1:
+            flags.add('NS_XRE_ENABLE_CRASH_REPORTER')
+    except: pass
+    appdata = dict(("%s:%s" % (s, o), config.get(s, o)) for s in config.sections() for o in config.options(s))
+    appdata['flags'] = ' | '.join(flags) if flags else '0'
+    appdata['App:profile'] = '"%s"' % appdata['App:profile'] if 'App:profile' in appdata else 'NULL'
+    expected = ('App:vendor', 'App:name', 'App:remotingname', 'App:version', 'App:buildid',
+                'App:id', 'Gecko:minversion', 'Gecko:maxversion')
+    missing = [var for var in expected if var not in appdata]
+    if missing:
+        print >>sys.stderr, \
+            "Missing values in %s: %s" % (file, ', '.join(missing))
+        sys.exit(1)
+
+    if not 'Crash Reporter:serverurl' in appdata:
+        appdata['Crash Reporter:serverurl'] = ''
+
+    print '''#include "nsXREAppData.h"
+             static const nsXREAppData sAppData = {
+                 sizeof(nsXREAppData),
+                 NULL, // directory
+                 "%(App:vendor)s",
+                 "%(App:name)s",
+                 "%(App:remotingname)s",
+                 "%(App:version)s",
+                 "%(App:buildid)s",
+                 "%(App:id)s",
+                 NULL, // copyright
+                 %(flags)s,
+                 NULL, // xreDirectory
+                 "%(Gecko:minversion)s",
+                 "%(Gecko:maxversion)s",
+                 "%(Crash Reporter:serverurl)s",
+                 %(App:profile)s
+             };''' % appdata
+
+if __name__ == '__main__':
+    if len(sys.argv) != 1:
+        main(sys.argv[1])
+    else:
+        print >>sys.stderr, "Usage: %s /path/to/application.ini" % sys.argv[0]
diff --git a/src/third_party/mozjs-45/build/application.ini b/src/third_party/mozjs-45/build/application.ini
new file mode 100644
index 0000000..74b0139
--- /dev/null
+++ b/src/third_party/mozjs-45/build/application.ini
@@ -0,0 +1,51 @@
+#if MOZ_APP_STATIC_INI
+#ifdef MOZ_BUILD_APP_IS_BROWSER
+; This file is not used. If you modify it and want the application to use
+; your modifications, move it under the browser/ subdirectory and start with
+; the "-app /path/to/browser/application.ini" argument.
+#else
+; This file is not used. If you modify it and want the application to use
+; your modifications, start with the "-app /path/to/application.ini"
+; argument.
+#endif
+#endif
+#if 0
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#endif
+#filter substitution
+[App]
+Vendor=@MOZ_APP_VENDOR@
+Name=@MOZ_APP_BASENAME@
+RemotingName=@MOZ_APP_REMOTINGNAME@
+#ifdef MOZ_APP_DISPLAYNAME
+CodeName=@MOZ_APP_DISPLAYNAME@
+#endif
+Version=@MOZ_APP_VERSION@
+#ifdef MOZ_APP_PROFILE
+Profile=@MOZ_APP_PROFILE@
+#endif
+BuildID=@MOZ_APP_BUILDID@
+#ifdef MOZ_SOURCE_REPO
+SourceRepository=@MOZ_SOURCE_REPO@
+#endif
+#ifdef MOZ_SOURCE_STAMP
+SourceStamp=@MOZ_SOURCE_STAMP@
+#endif
+ID=@MOZ_APP_ID@
+
+[Gecko]
+MinVersion=@GRE_MILESTONE@
+MaxVersion=@GRE_MILESTONE@
+
+[XRE]
+#ifdef MOZ_PROFILE_MIGRATOR
+EnableProfileMigrator=1
+#endif
+
+#if MOZ_CRASHREPORTER
+[Crash Reporter]
+Enabled=1
+ServerURL=https://crash-reports.mozilla.com/submit?id=@MOZ_APP_ID@&version=@MOZ_APP_VERSION@&buildid=@MOZ_APP_BUILDID@
+#endif
diff --git a/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4 b/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4
new file mode 100644
index 0000000..ad9c754
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4
@@ -0,0 +1,31 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+define(GENERATE_SUB_ABS, [
+define([AC_OUTPUT_FILES_SUB1], [
+patsubst($@, [/\*)], [/* | ?:/*)])
+])
+])
+GENERATE_SUB_ABS(defn([AC_OUTPUT_FILES]))
+
+define(GENERATE_SUB_NOSPLIT, [
+define([AC_OUTPUT_FILES], [
+patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], [])
+])
+])
+GENERATE_SUB_NOSPLIT(defn([AC_OUTPUT_FILES_SUB1]))
+
+define(GENERATE_HEADER_NOSPLIT, [
+define([AC_OUTPUT_HEADER], [
+patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], [])
+])
+])
+GENERATE_HEADER_NOSPLIT(defn([AC_OUTPUT_HEADER]))
+
+define(GENERATE_SUBDIRS_ABS, [
+define([AC_OUTPUT_SUBDIRS], [
+patsubst($@, [/\*)], [/* | ?:/*)])
+])
+])
+GENERATE_SUBDIRS_ABS(defn([AC_OUTPUT_SUBDIRS]))
diff --git a/src/third_party/mozjs-45/build/autoconf/alloc.m4 b/src/third_party/mozjs-45/build/autoconf/alloc.m4
new file mode 100644
index 0000000..8234a60
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/alloc.m4
@@ -0,0 +1,53 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Check for the existence of various allocation headers/functions
+AC_DEFUN([MOZ_CHECK_ALLOCATOR],[
+
+MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h"
+MALLOC_H=
+
+for file in $MALLOC_HEADERS; do
+  MOZ_CHECK_HEADER($file, [MALLOC_H=$file])
+  if test "$MALLOC_H" != ""; then
+    AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>)
+    break
+  fi
+done
+
+MOZ_CHECK_HEADERS(alloca.h)
+
+AC_CHECK_FUNCS(strndup posix_memalign memalign)
+
+AC_CHECK_FUNCS(malloc_usable_size)
+MALLOC_USABLE_SIZE_CONST_PTR=const
+MOZ_CHECK_HEADERS([malloc.h], [
+  AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument])
+  AC_TRY_COMPILE([#include <malloc.h>
+                  #include <stddef.h>
+                  size_t malloc_usable_size(const void *ptr);],
+                  [return malloc_usable_size(0);],
+                  AC_MSG_RESULT([yes]),
+                  AC_MSG_RESULT([no])
+                  MALLOC_USABLE_SIZE_CONST_PTR=)
+])
+AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR])
+
+
+dnl In newer bionic headers, valloc is built but not defined,
+dnl so we check more carefully here.
+AC_MSG_CHECKING([for valloc in malloc.h])
+AC_EGREP_HEADER(valloc, malloc.h,
+                AC_DEFINE(HAVE_VALLOC)
+                AC_MSG_RESULT([yes]),
+                AC_MSG_RESULT([no]))
+
+AC_MSG_CHECKING([for valloc in unistd.h])
+AC_EGREP_HEADER(valloc, unistd.h,
+                AC_DEFINE(HAVE_VALLOC)
+                AC_MSG_RESULT([yes]),
+                AC_MSG_RESULT([no]))
+
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/altoptions.m4 b/src/third_party/mozjs-45/build/autoconf/altoptions.m4
new file mode 100644
index 0000000..f8c8ba9
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/altoptions.m4
@@ -0,0 +1,123 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl altoptions.m4 - An alternative way of specifying command-line options.
+dnl    These macros are needed to support a menu-based configurator.
+dnl    This file also includes the macro, AM_READ_MYCONFIG, for reading
+dnl    the 'myconfig.m4' file.
+
+dnl Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com).
+
+
+dnl MOZ_ARG_ENABLE_BOOL(           NAME, HELP, IF-YES [, IF-NO [, ELSE]])
+dnl MOZ_ARG_DISABLE_BOOL(          NAME, HELP, IF-NO [, IF-YES [, ELSE]])
+dnl MOZ_ARG_ENABLE_STRING(         NAME, HELP, IF-SET [, ELSE])
+dnl MOZ_ARG_ENABLE_BOOL_OR_STRING( NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]])
+dnl MOZ_ARG_WITH_BOOL(             NAME, HELP, IF-YES [, IF-NO [, ELSE])
+dnl MOZ_ARG_WITHOUT_BOOL(          NAME, HELP, IF-NO [, IF-YES [, ELSE])
+dnl MOZ_ARG_WITH_STRING(           NAME, HELP, IF-SET [, ELSE])
+dnl MOZ_ARG_HEADER(Comment)
+dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
+
+
+dnl MOZ_TWO_STRING_TEST(NAME, VAL, STR1, IF-STR1, STR2, IF-STR2 [, ELSE])
+AC_DEFUN([MOZ_TWO_STRING_TEST],
+[if test "[$2]" = "[$3]"; then
+    ifelse([$4], , :, [$4])
+  elif test "[$2]" = "[$5]"; then
+    ifelse([$6], , :, [$6])
+  else
+    ifelse([$7], ,
+      [AC_MSG_ERROR([Option, [$1], does not take an argument ([$2]).])],
+      [$7])
+  fi])
+
+dnl MOZ_ARG_ENABLE_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]])
+AC_DEFUN([MOZ_ARG_ENABLE_BOOL],
+[AC_ARG_ENABLE([$1], [$2], 
+ [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_DISABLE_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]])
+AC_DEFUN([MOZ_ARG_DISABLE_BOOL],
+[AC_ARG_ENABLE([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$enableval], no, [$3], yes, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_ENABLE_STRING(NAME, HELP, IF-SET [, ELSE])
+AC_DEFUN([MOZ_ARG_ENABLE_STRING],
+[AC_ARG_ENABLE([$1], [$2], [$3], [$4])])
+
+dnl MOZ_ARG_ENABLE_BOOL_OR_STRING(NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]])
+AC_DEFUN([MOZ_ARG_ENABLE_BOOL_OR_STRING],
+[ifelse([$5], , 
+ [errprint([Option, $1, needs an "IF-SET" argument.
+])
+  m4exit(1)],
+ [AC_ARG_ENABLE([$1], [$2],
+  [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4], [$5])],
+  [$6])])])
+
+dnl MOZ_ARG_WITH_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE])
+AC_DEFUN([MOZ_ARG_WITH_BOOL],
+[AC_ARG_WITH([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$withval], yes, [$3], no, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_WITHOUT_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE])
+AC_DEFUN([MOZ_ARG_WITHOUT_BOOL],
+[AC_ARG_WITH([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$withval], no, [$3], yes, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_WITH_STRING(NAME, HELP, IF-SET [, ELSE])
+AC_DEFUN([MOZ_ARG_WITH_STRING],
+[AC_ARG_WITH([$1], [$2], [$3], [$4])])
+
+dnl MOZ_ARG_HEADER(Comment)
+dnl This is used by webconfig to group options
+define(MOZ_ARG_HEADER, [# $1])
+
+dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
+AC_DEFUN([MOZ_READ_MOZCONFIG],
+[AC_REQUIRE([AC_INIT_BINSH])dnl
+inserted=
+dnl Shell is hard, so here is what the following does:
+dnl - Reset $@ (command line arguments)
+dnl - Add the configure options from mozconfig to $@ one by one
+dnl - Add the original command line arguments after that, one by one
+dnl
+dnl There are several tricks involved:
+dnl - It is not possible to preserve the whitespaces in $@ by assigning to
+dnl   another variable, so the two first steps above need to happen in the first
+dnl   iteration of the third step.
+dnl - We always want the configure options to be added, so the loop must be
+dnl   iterated at least once, so we add a dummy argument first, and discard it.
+dnl - something | while read line ... makes the while run in a subshell, meaning
+dnl   that anything it does is not propagated to the main shell, so we can't do
+dnl   set -- foo there. As a consequence, what the while loop reading mach
+dnl   environment output does is output a set of shell commands for the main shell
+dnl   to eval.
+dnl - Extra care is due when lines from mach environment output contain special
+dnl   shell characters, so we use ' for quoting and ensure no ' end up in between
+dnl   the quoting mark unescaped.
+dnl Some of the above is directly done in mach environment --format=configure.
+failed_eval() {
+  echo "Failed eval'ing the following:"
+  $(dirname [$]0)/[$1]/mach environment --format=configure
+  exit 1
+}
+
+set -- dummy "[$]@"
+for ac_option
+do
+  if test -z "$inserted"; then
+    set --
+    eval "$($(dirname [$]0)/[$1]/mach environment --format=configure)" || failed_eval
+    inserted=1
+  else
+    set -- "[$]@" "$ac_option"
+  fi
+done
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/android.m4 b/src/third_party/mozjs-45/build/autoconf/android.m4
new file mode 100644
index 0000000..f5d7430
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/android.m4
@@ -0,0 +1,512 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_ANDROID_NDK],
+[
+
+MOZ_ARG_WITH_STRING(android-ndk,
+[  --with-android-ndk=DIR
+                          location where the Android NDK can be found],
+    android_ndk=$withval)
+
+MOZ_ARG_WITH_STRING(android-toolchain,
+[  --with-android-toolchain=DIR
+                          location of the Android toolchain],
+    android_toolchain=$withval)
+
+MOZ_ARG_WITH_STRING(android-gnu-compiler-version,
+[  --with-android-gnu-compiler-version=VER
+                          gnu compiler version to use],
+    android_gnu_compiler_version=$withval)
+
+MOZ_ARG_WITH_STRING(android-cxx-stl,
+[  --with-android-cxx-stl=VALUE
+                          use the specified C++ STL (stlport, libstdc++, libc++)],
+    android_cxx_stl=$withval,
+    android_cxx_stl=mozstlport)
+
+define([MIN_ANDROID_VERSION], [9])
+android_version=MIN_ANDROID_VERSION
+
+MOZ_ARG_WITH_STRING(android-version,
+[  --with-android-version=VER
+                          android platform version, default] MIN_ANDROID_VERSION,
+    android_version=$withval)
+
+if test $android_version -lt MIN_ANDROID_VERSION ; then
+    AC_MSG_ERROR([--with-android-version must be at least MIN_ANDROID_VERSION.])
+fi
+
+case "$target" in
+arm-*linux*-android*|*-linuxandroid*)
+    android_tool_prefix="arm-linux-androideabi"
+    ;;
+i?86-*android*)
+    android_tool_prefix="i686-linux-android"
+    ;;
+mipsel-*android*)
+    android_tool_prefix="mipsel-linux-android"
+    ;;
+*)
+    android_tool_prefix="$target_os"
+    ;;
+esac
+
+case "$target" in
+*-android*|*-linuxandroid*)
+    if test -z "$android_ndk" ; then
+        AC_MSG_ERROR([You must specify --with-android-ndk=/path/to/ndk when targeting Android.])
+    fi
+
+    if test -z "$android_toolchain" ; then
+        AC_MSG_CHECKING([for android toolchain directory])
+
+        kernel_name=`uname -s | tr "[[:upper:]]" "[[:lower:]]"`
+
+        for version in $android_gnu_compiler_version 4.9 4.8 4.7; do
+            case "$target_cpu" in
+            arm)
+                target_name=arm-linux-androideabi-$version
+                ;;
+            i?86)
+                target_name=x86-$version
+                ;;
+            mipsel)
+                target_name=mipsel-linux-android-$version
+                ;;
+            *)
+                AC_MSG_ERROR([target cpu is not supported])
+                ;;
+            esac
+            case "$host_cpu" in
+            i*86)
+                android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86
+                ;;
+            x86_64)
+                android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86_64
+                if ! test -d "$android_toolchain" ; then
+                    android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86
+                fi
+                ;;
+            *)
+                AC_MSG_ERROR([No known toolchain for your host cpu])
+                ;;
+            esac
+            if test -d "$android_toolchain" ; then
+                android_gnu_compiler_version=$version
+                break
+            elif test -n "$android_gnu_compiler_version" ; then
+                AC_MSG_ERROR([not found. Your --with-android-gnu-compiler-version may be wrong.])
+            fi
+        done
+
+        if test -z "$android_gnu_compiler_version" ; then
+            AC_MSG_ERROR([not found. You have to specify --with-android-toolchain=/path/to/ndk/toolchain.])
+        else
+            AC_MSG_RESULT([$android_toolchain])
+        fi
+        NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-android-toolchain=$android_toolchain"
+    fi
+
+    NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-android-version=$android_version"
+
+    AC_MSG_CHECKING([for android platform directory])
+
+    case "$target_cpu" in
+    arm)
+        target_name=arm
+        ;;
+    i?86)
+        target_name=x86
+        ;;
+    mipsel)
+        target_name=mips
+        ;;
+    esac
+
+    android_platform="$android_ndk"/platforms/android-"$android_version"/arch-"$target_name"
+
+    if test -d "$android_platform" ; then
+        AC_MSG_RESULT([$android_platform])
+    else
+        AC_MSG_ERROR([not found. Please check your NDK. With the current configuration, it should be in $android_platform])
+    fi
+
+    dnl set up compilers
+    TOOLCHAIN_PREFIX="$android_toolchain/bin/$android_tool_prefix-"
+    AS="$android_toolchain"/bin/"$android_tool_prefix"-as
+    if test -z "$CC"; then
+        CC="$android_toolchain"/bin/"$android_tool_prefix"-gcc
+    fi
+    if test -z "$CXX"; then
+        CXX="$android_toolchain"/bin/"$android_tool_prefix"-g++
+    fi
+    if test -z "$CPP"; then
+        CPP="$android_toolchain"/bin/"$android_tool_prefix"-cpp
+    fi
+    LD="$android_toolchain"/bin/"$android_tool_prefix"-ld
+    AR="$android_toolchain"/bin/"$android_tool_prefix"-ar
+    RANLIB="$android_toolchain"/bin/"$android_tool_prefix"-ranlib
+    STRIP="$android_toolchain"/bin/"$android_tool_prefix"-strip
+    OBJCOPY="$android_toolchain"/bin/"$android_tool_prefix"-objcopy
+
+    CPPFLAGS="-idirafter $android_platform/usr/include $CPPFLAGS"
+    CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
+    CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS"
+    ASFLAGS="-idirafter $android_platform/usr/include -DANDROID $ASFLAGS"
+
+    dnl Add -llog by default, since we use it all over the place.
+    dnl Add --allow-shlib-undefined, because libGLESv2 links to an
+    dnl undefined symbol (present on the hardware, just not in the
+    dnl NDK.)
+    LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -llog -Wl,--allow-shlib-undefined $LDFLAGS"
+    dnl prevent cross compile section from using these flags as host flags
+    if test -z "$HOST_CPPFLAGS" ; then
+        HOST_CPPFLAGS=" "
+    fi
+    if test -z "$HOST_CFLAGS" ; then
+        HOST_CFLAGS=" "
+    fi
+    if test -z "$HOST_CXXFLAGS" ; then
+        HOST_CXXFLAGS=" "
+    fi
+    if test -z "$HOST_LDFLAGS" ; then
+        HOST_LDFLAGS=" "
+    fi
+
+    ANDROID_NDK="${android_ndk}"
+    ANDROID_TOOLCHAIN="${android_toolchain}"
+    ANDROID_PLATFORM="${android_platform}"
+
+    AC_DEFINE(ANDROID)
+    AC_SUBST(ANDROID_NDK)
+    AC_SUBST(ANDROID_TOOLCHAIN)
+    AC_SUBST(ANDROID_PLATFORM)
+
+    ;;
+esac
+
+])
+
+AC_DEFUN([MOZ_ANDROID_CPU_ARCH],
+[
+
+if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then
+    case "${CPU_ARCH}-${MOZ_ARCH}" in
+    arm-armv7*)
+        ANDROID_CPU_ARCH=armeabi-v7a
+        ;;
+    arm-*)
+        ANDROID_CPU_ARCH=armeabi
+        ;;
+    x86-*)
+        ANDROID_CPU_ARCH=x86
+        ;;
+    mips-*) # When target_cpu is mipsel, CPU_ARCH is mips
+        ANDROID_CPU_ARCH=mips
+        ;;
+    esac
+
+    AC_SUBST(ANDROID_CPU_ARCH)
+fi
+])
+
+AC_DEFUN([MOZ_ANDROID_STLPORT],
+[
+
+if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then
+    cpu_arch_dir="$ANDROID_CPU_ARCH"
+    if test "$MOZ_THUMB2" = 1; then
+        cpu_arch_dir="$cpu_arch_dir/thumb"
+    fi
+
+    if test -z "$STLPORT_CPPFLAGS$STLPORT_LIBS"; then
+        case "$android_cxx_stl" in
+        libstdc++)
+            # android-ndk-r8b and later
+            ndk_base="$android_ndk/sources/cxx-stl/gnu-libstdc++/$android_gnu_compiler_version"
+            ndk_libs_include="$ndk_base/libs/$ANDROID_CPU_ARCH"
+            ndk_libs="$ndk_base/libs/$cpu_arch_dir"
+            ndk_include="$ndk_base/include"
+
+            if ! test -e "$ndk_libs/libgnustl_static.a"; then
+                AC_MSG_ERROR([Couldn't find path to gnu-libstdc++ in the android ndk])
+            fi
+
+            STLPORT_LIBS="-L$ndk_libs -lgnustl_static"
+            STLPORT_CPPFLAGS="-I$ndk_include -I$ndk_include/backward -I$ndk_libs_include/include"
+            ;;
+        libc++)
+            # android-ndk-r8b and later
+            ndk_base="$android_ndk/sources/cxx-stl"
+            cxx_base="$ndk_base/llvm-libc++"
+            cxx_libs="$cxx_base/libs/$cpu_arch_dir"
+            cxx_include="$cxx_base/libcxx/include"
+            cxxabi_base="$ndk_base/llvm-libc++abi"
+            cxxabi_include="$cxxabi_base/libcxxabi/include"
+
+            if ! test -e "$cxx_libs/libc++_static.a"; then
+                AC_MSG_ERROR([Couldn't find path to llvm-libc++ in the android ndk])
+            fi
+
+            STLPORT_LIBS="-L$cxx_libs -lc++_static"
+            # Add android/support/include/ for prototyping long double math
+            # functions, locale-specific C library functions, multibyte support,
+            # etc.
+            STLPORT_CPPFLAGS="-I$android_ndk/sources/android/support/include -I$cxx_include -I$cxxabi_include"
+            ;;
+        mozstlport)
+            # We don't need to set STLPORT_LIBS, because the build system will
+            # take care of linking in our home-built stlport where it is needed.
+            STLPORT_CPPFLAGS="-isystem $_topsrcdir/build/stlport/stlport -isystem $_topsrcdir/build/stlport/overrides -isystem $android_ndk/sources/cxx-stl/system/include"
+            ;;
+        *)
+            AC_MSG_ERROR([Bad value for --enable-android-cxx-stl])
+            ;;
+        esac
+    fi
+    CXXFLAGS="$CXXFLAGS $STLPORT_CPPFLAGS"
+fi
+MOZ_ANDROID_CXX_STL=$android_cxx_stl
+AC_SUBST([MOZ_ANDROID_CXX_STL])
+AC_SUBST([STLPORT_LIBS])
+
+])
+
+
+AC_DEFUN([concat],[$1$2$3$4])
+
+dnl Find a component of an AAR.
+dnl Arg 1: variable name to expose, like ANDROID_SUPPORT_V4_LIB.
+dnl Arg 2: path to component.
+dnl Arg 3: if non-empty, expect and require component.
+AC_DEFUN([MOZ_ANDROID_AAR_COMPONENT], [
+  ifelse([$3], ,
+  [
+    if test -e "$$1" ; then
+      AC_MSG_ERROR([Found unexpected exploded $1!])
+    fi
+  ],
+  [
+    AC_MSG_CHECKING([for $1])
+    $1="$2"
+    if ! test -e "$$1" ; then
+      AC_MSG_ERROR([Could not find required exploded $1!])
+    fi
+    AC_MSG_RESULT([$$1])
+    AC_SUBST($1)
+  ])
+])
+
+dnl Find an AAR and expose variables representing its exploded components.
+dnl AC_SUBSTs ANDROID_NAME_{AAR,AAR_RES,AAR_LIB,AAR_INTERNAL_LIB}.
+dnl Arg 1: name, like play-services-base
+dnl Arg 2: version, like 7.8.0
+dnl Arg 3: extras subdirectory, either android or google
+dnl Arg 4: package subdirectory, like com/google/android/gms
+dnl Arg 5: if non-empty, expect and require internal_impl JAR.
+dnl Arg 6: if non-empty, expect and require assets/ directory.
+AC_DEFUN([MOZ_ANDROID_AAR],[
+  define([local_aar_var_base], translit($1, [-a-z], [_A-Z]))
+  define([local_aar_var], concat(ANDROID_, local_aar_var_base, _AAR))
+  local_aar_var="$ANDROID_SDK_ROOT/extras/$3/m2repository/$4/$1/$2/$1-$2.aar"
+  AC_MSG_CHECKING([for $1 AAR])
+  if ! test -e "$local_aar_var" ; then
+    AC_MSG_ERROR([You must download the $1 AAR.  Run the Android SDK tool and install the Android and Google Support Repositories under Extras.  See https://developer.android.com/tools/extras/support-library.html for more info. (Looked for $local_aar_var)])
+  fi
+  AC_SUBST(local_aar_var)
+  AC_MSG_RESULT([$local_aar_var])
+
+  if ! $PYTHON -m mozbuild.action.explode_aar --destdir=$MOZ_BUILD_ROOT/dist/exploded-aar $local_aar_var ; then
+    AC_MSG_ERROR([Could not explode $local_aar_var!])
+  fi
+
+  define([root], $MOZ_BUILD_ROOT/dist/exploded-aar/$1-$2/)
+  MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _LIB), concat(root, $1-$2-classes.jar), REQUIRED)
+  MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _RES), concat(root, res), REQUIRED)
+  MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _INTERNAL_LIB), concat(root, libs/$1-$2-internal_impl-$2.jar), $5)
+  MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _ASSETS), concat(root, assets), $6)
+])
+
+AC_DEFUN([MOZ_ANDROID_GOOGLE_PLAY_SERVICES],
+[
+
+if test -n "$MOZ_NATIVE_DEVICES" ; then
+    AC_SUBST(MOZ_NATIVE_DEVICES)
+
+    MOZ_ANDROID_AAR(play-services-base, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-cast, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(mediarouter-v7, 23.0.1, android, com/android/support, REQUIRED_INTERNAL_IMPL)
+fi
+
+])
+
+AC_DEFUN([MOZ_ANDROID_GOOGLE_CLOUD_MESSAGING],
+[
+
+if test -n "$MOZ_ANDROID_GCM" ; then
+    AC_SUBST(MOZ_ANDROID_GCM)
+
+    MOZ_ANDROID_AAR(play-services-base, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-gcm, 8.1.0, google, com/google/android/gms)
+fi
+
+])
+
+AC_DEFUN([MOZ_ANDROID_INSTALL_TRACKING],
+[
+
+if test -n "$MOZ_INSTALL_TRACKING"; then
+    AC_SUBST(MOZ_INSTALL_TRACKING)
+    MOZ_ANDROID_AAR(play-services-ads, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-analytics, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-appindexing, 8.1.0, google, com/google/android/gms)
+    MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+fi
+
+])
+
+dnl Configure an Android SDK.
+dnl Arg 1: target SDK version, like 22.
+dnl Arg 2: build tools version, like 22.0.1.
+AC_DEFUN([MOZ_ANDROID_SDK],
+[
+
+MOZ_ARG_WITH_STRING(android-sdk,
+[  --with-android-sdk=DIR
+                          location where the Android SDK can be found (like ~/.mozbuild/android-sdk-linux)],
+    android_sdk_root=$withval)
+
+android_sdk_root=${withval%/platforms/android-*}
+
+case "$target" in
+*-android*|*-linuxandroid*)
+    if test -z "$android_sdk_root" ; then
+        AC_MSG_ERROR([You must specify --with-android-sdk=/path/to/sdk when targeting Android.])
+    fi
+
+    # We were given an old-style
+    # --with-android-sdk=/path/to/sdk/platforms/android-*.  We could warn, but
+    # we'll get compliance by forcing the issue.
+    if test -e "$withval"/source.properties ; then
+        AC_MSG_ERROR([Including platforms/android-* in --with-android-sdk arguments is deprecated.  Use --with-android-sdk=$android_sdk_root.])
+    fi
+
+    android_target_sdk=$1
+    AC_MSG_CHECKING([for Android SDK platform version $android_target_sdk])
+    android_sdk=$android_sdk_root/platforms/android-$android_target_sdk
+    if ! test -e "$android_sdk/source.properties" ; then
+        AC_MSG_ERROR([You must download Android SDK platform version $android_target_sdk.  Try |mach bootstrap|.  (Looked for $android_sdk)])
+    fi
+    AC_MSG_RESULT([$android_sdk])
+
+    android_build_tools="$android_sdk_root"/build-tools/$2
+    AC_MSG_CHECKING([for Android build-tools version $2])
+    if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then
+        AC_MSG_RESULT([$android_build_tools])
+    else
+        AC_MSG_ERROR([You must install the Android build-tools version $2.  Try |mach bootstrap|.  (Looked for $android_build_tools)])
+    fi
+
+    MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$android_build_tools])
+    MOZ_PATH_PROG(DX, dx, :, [$android_build_tools])
+    MOZ_PATH_PROG(AAPT, aapt, :, [$android_build_tools])
+    MOZ_PATH_PROG(AIDL, aidl, :, [$android_build_tools])
+    if test -z "$ZIPALIGN" -o "$ZIPALIGN" = ":"; then
+      AC_MSG_ERROR([The program zipalign was not found.  Try |mach bootstrap|.])
+    fi
+    if test -z "$DX" -o "$DX" = ":"; then
+      AC_MSG_ERROR([The program dx was not found.  Try |mach bootstrap|.])
+    fi
+    if test -z "$AAPT" -o "$AAPT" = ":"; then
+      AC_MSG_ERROR([The program aapt was not found.  Try |mach bootstrap|.])
+    fi
+    if test -z "$AIDL" -o "$AIDL" = ":"; then
+      AC_MSG_ERROR([The program aidl was not found.  Try |mach bootstrap|.])
+    fi
+
+    android_platform_tools="$android_sdk_root"/platform-tools
+    AC_MSG_CHECKING([for Android platform-tools])
+    if test -d "$android_platform_tools" -a -f "$android_platform_tools/adb"; then
+        AC_MSG_RESULT([$android_platform_tools])
+    else
+        AC_MSG_ERROR([You must install the Android platform-tools.  Try |mach bootstrap|.  (Looked for $android_platform_tools)])
+    fi
+
+    MOZ_PATH_PROG(ADB, adb, :, [$android_platform_tools])
+    if test -z "$ADB" -o "$ADB" = ":"; then
+      AC_MSG_ERROR([The program adb was not found.  Try |mach bootstrap|.])
+    fi
+
+    android_tools="$android_sdk_root"/tools
+    AC_MSG_CHECKING([for Android tools])
+    if test -d "$android_tools" -a -f "$android_tools/emulator"; then
+        AC_MSG_RESULT([$android_tools])
+    else
+        AC_MSG_ERROR([You must install the Android tools.  Try |mach bootstrap|.  (Looked for $android_tools)])
+    fi
+
+    MOZ_PATH_PROG(EMULATOR, emulator, :, [$android_tools])
+    if test -z "$EMULATOR" -o "$EMULATOR" = ":"; then
+      AC_MSG_ERROR([The program emulator was not found.  Try |mach bootstrap|.])
+    fi
+
+    ANDROID_TARGET_SDK="${android_target_sdk}"
+    ANDROID_SDK="${android_sdk}"
+    ANDROID_SDK_ROOT="${android_sdk_root}"
+    ANDROID_TOOLS="${android_tools}"
+    AC_DEFINE_UNQUOTED(ANDROID_TARGET_SDK,$ANDROID_TARGET_SDK)
+    AC_SUBST(ANDROID_TARGET_SDK)
+    AC_SUBST(ANDROID_SDK_ROOT)
+    AC_SUBST(ANDROID_SDK)
+    AC_SUBST(ANDROID_TOOLS)
+
+    MOZ_ANDROID_AAR(appcompat-v7, 23.0.1, android, com/android/support)
+    MOZ_ANDROID_AAR(design, 23.0.1, android, com/android/support)
+    MOZ_ANDROID_AAR(recyclerview-v7, 23.0.1, android, com/android/support)
+    MOZ_ANDROID_AAR(support-v4, 23.0.1, android, com/android/support, REQUIRED_INTERNAL_IMPL)
+
+    ANDROID_SUPPORT_ANNOTATIONS_JAR="$ANDROID_SDK_ROOT/extras/android/m2repository/com/android/support/support-annotations/23.0.1/support-annotations-23.0.1.jar"
+    AC_MSG_CHECKING([for support-annotations JAR])
+    if ! test -e $ANDROID_SUPPORT_ANNOTATIONS_JAR ; then
+        AC_MSG_ERROR([You must download the support-annotations lib.  Run the Android SDK tool and install the Android Support Repository under Extras.  See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_SUPPORT_ANNOTATIONS_JAR)])
+    fi
+    AC_MSG_RESULT([$ANDROID_SUPPORT_ANNOTATIONS_JAR])
+    AC_SUBST(ANDROID_SUPPORT_ANNOTATIONS_JAR)
+    ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB=$ANDROID_SUPPORT_ANNOTATIONS_JAR
+    AC_SUBST(ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB)
+    ;;
+esac
+
+MOZ_ARG_WITH_STRING(android-min-sdk,
+[  --with-android-min-sdk=[VER]     Impose a minimum Firefox for Android SDK version],
+[ MOZ_ANDROID_MIN_SDK_VERSION=$withval ])
+
+MOZ_ARG_WITH_STRING(android-max-sdk,
+[  --with-android-max-sdk=[VER]     Impose a maximum Firefox for Android SDK version],
+[ MOZ_ANDROID_MAX_SDK_VERSION=$withval ])
+
+if test -n "$MOZ_ANDROID_MIN_SDK_VERSION"; then
+    if test -n "$MOZ_ANDROID_MAX_SDK_VERSION"; then
+        if test $MOZ_ANDROID_MAX_SDK_VERSION -lt $MOZ_ANDROID_MIN_SDK_VERSION ; then
+            AC_MSG_ERROR([--with-android-max-sdk must be at least the value of --with-android-min-sdk.])
+        fi
+    fi
+
+    if test $MOZ_ANDROID_MIN_SDK_VERSION -gt $ANDROID_TARGET_SDK ; then
+        AC_MSG_ERROR([--with-android-min-sdk is expected to be less than $ANDROID_TARGET_SDK])
+    fi
+
+    AC_DEFINE_UNQUOTED(MOZ_ANDROID_MIN_SDK_VERSION, $MOZ_ANDROID_MIN_SDK_VERSION)
+    AC_SUBST(MOZ_ANDROID_MIN_SDK_VERSION)
+fi
+
+if test -n "$MOZ_ANDROID_MAX_SDK_VERSION"; then
+    AC_DEFINE_UNQUOTED(MOZ_ANDROID_MAX_SDK_VERSION, $MOZ_ANDROID_MAX_SDK_VERSION)
+    AC_SUBST(MOZ_ANDROID_MAX_SDK_VERSION)
+fi
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/arch.m4 b/src/third_party/mozjs-45/build/autoconf/arch.m4
new file mode 100644
index 0000000..b62ea71
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/arch.m4
@@ -0,0 +1,260 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_ARCH_OPTS],
+[
+
+dnl ========================================================
+dnl = ARM toolchain tweaks
+dnl ========================================================
+
+MOZ_THUMB=toolchain-default
+MOZ_THUMB_INTERWORK=toolchain-default
+MOZ_FPU=toolchain-default
+MOZ_FLOAT_ABI=toolchain-default
+MOZ_SOFT_FLOAT=toolchain-default
+MOZ_ALIGN=toolchain-default
+
+MOZ_ARG_WITH_STRING(arch,
+[  --with-arch=[[type|toolchain-default]]
+                           Use specific CPU features (-march=type). Resets
+                           thumb, fpu, float-abi, etc. defaults when set],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-arch is not supported on non-GNU toolchains])
+    fi
+    MOZ_ARCH=$withval)
+
+if test -z "$MOZ_ARCH"; then
+    dnl Defaults
+    case "${CPU_ARCH}-${OS_TARGET}" in
+    arm-Android)
+        MOZ_THUMB=yes
+        MOZ_ARCH=armv7-a
+        MOZ_FPU=vfp
+        MOZ_FLOAT_ABI=softfp
+        MOZ_ALIGN=no
+        ;;
+    arm-Darwin)
+        MOZ_ARCH=toolchain-default
+        ;;
+    esac
+fi
+
+if test "$MOZ_ARCH" = "armv6" -a "$OS_TARGET" = "Android"; then
+   MOZ_FPU=vfp
+fi
+
+MOZ_ARG_WITH_STRING(thumb,
+[  --with-thumb[[=yes|no|toolchain-default]]]
+[                          Use Thumb instruction set (-mthumb)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB=$withval)
+
+MOZ_ARG_WITH_STRING(thumb-interwork,
+[  --with-thumb-interwork[[=yes|no|toolchain-default]]
+                           Use Thumb/ARM instuctions interwork (-mthumb-interwork)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb-interwork is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB_INTERWORK=$withval)
+
+MOZ_ARG_WITH_STRING(fpu,
+[  --with-fpu=[[type|toolchain-default]]
+                           Use specific FPU type (-mfpu=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-fpu is not supported on non-GNU toolchains])
+    fi
+    MOZ_FPU=$withval)
+
+MOZ_ARG_WITH_STRING(float-abi,
+[  --with-float-abi=[[type|toolchain-default]]
+                           Use specific arm float ABI (-mfloat-abi=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-float-abi is not supported on non-GNU toolchains])
+    fi
+    MOZ_FLOAT_ABI=$withval)
+
+MOZ_ARG_WITH_STRING(soft-float,
+[  --with-soft-float[[=yes|no|toolchain-default]]
+                           Use soft float library (-msoft-float)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-soft-float is not supported on non-GNU toolchains])
+    fi
+    MOZ_SOFT_FLOAT=$withval)
+
+case "$MOZ_ARCH" in
+toolchain-default|"")
+    arch_flag=""
+    ;;
+*)
+    arch_flag="-march=$MOZ_ARCH"
+    ;;
+esac
+
+case "$MOZ_THUMB" in
+yes)
+    MOZ_THUMB2=1
+    thumb_flag="-mthumb"
+    ;;
+no)
+    MOZ_THUMB2=
+    thumb_flag="-marm"
+    ;;
+*)
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$arch_flag"
+    AC_TRY_COMPILE([],[return sizeof(__thumb2__);],
+        MOZ_THUMB2=1,
+        MOZ_THUMB2=)
+    CFLAGS="$_SAVE_CFLAGS"
+    thumb_flag=""
+    ;;
+esac
+
+if test "$MOZ_THUMB2" = 1; then
+    AC_DEFINE(MOZ_THUMB2)
+fi
+
+case "$MOZ_THUMB_INTERWORK" in
+yes)
+    thumb_interwork_flag="-mthumb-interwork"
+    ;;
+no)
+    thumb_interwork_flag="-mno-thumb-interwork"
+    ;;
+*) # toolchain-default
+    thumb_interwork_flag=""
+    ;;
+esac
+
+case "$MOZ_FPU" in
+toolchain-default|"")
+    fpu_flag=""
+    ;;
+*)
+    fpu_flag="-mfpu=$MOZ_FPU"
+    ;;
+esac
+
+case "$MOZ_FLOAT_ABI" in
+toolchain-default|"")
+    float_abi_flag=""
+    ;;
+*)
+    float_abi_flag="-mfloat-abi=$MOZ_FLOAT_ABI"
+    ;;
+esac
+
+case "$MOZ_SOFT_FLOAT" in
+yes)
+    soft_float_flag="-msoft-float"
+    ;;
+no)
+    soft_float_flag="-mno-soft-float"
+    ;;
+*) # toolchain-default
+    soft_float_flag=""
+    ;;
+esac
+
+case "$MOZ_ALIGN" in
+no)
+    align_flag="-mno-unaligned-access"
+    ;;
+yes)
+    align_flag="-munaligned-access"
+    ;;
+*)
+    align_flag=""
+    ;;
+esac
+
+if test -n "$align_flag"; then
+  _SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $align_flag"
+  AC_MSG_CHECKING(whether alignment flag ($align_flag) is supported)
+  AC_TRY_COMPILE([],[],,align_flag="")
+  CFLAGS="$_SAVE_CFLAGS"
+fi
+
+dnl Use echo to avoid accumulating space characters
+all_flags=`echo $arch_flag $thumb_flag $thumb_interwork_flag $fpu_flag $float_abi_flag $soft_float_flag $align_flag`
+if test -n "$all_flags"; then
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$all_flags"
+    AC_MSG_CHECKING(whether the chosen combination of compiler flags ($all_flags) works)
+    AC_TRY_COMPILE([],[return 0;],
+        AC_MSG_RESULT([yes]),
+        AC_MSG_ERROR([no]))
+
+    CFLAGS="$_SAVE_CFLAGS $all_flags"
+    CXXFLAGS="$CXXFLAGS $all_flags"
+    ASFLAGS="$ASFLAGS $all_flags"
+    if test -n "$thumb_flag"; then
+        LDFLAGS="$LDFLAGS $thumb_flag"
+    fi
+fi
+
+AC_SUBST(MOZ_THUMB2)
+
+if test "$CPU_ARCH" = "arm"; then
+  AC_MSG_CHECKING(for ARM SIMD support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm("uqadd8 r1, r1, r2");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_SIMD)
+      HAVE_ARM_SIMD=1
+  fi
+
+  AC_MSG_CHECKING(ARM version support in compiler)
+  dnl Determine the target ARM architecture (5 for ARMv5, v5T, v5E, etc.; 6 for ARMv6, v6K, etc.)
+  ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]][[0-9]]*\).*/\1/p'`
+  AC_MSG_RESULT("$ARM_ARCH")
+
+  AC_MSG_CHECKING(for ARM NEON support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm(".fpu neon\n vadd.i8 d0, d0, d0");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_NEON)
+      HAVE_ARM_NEON=1
+
+      dnl We don't need to build NEON support if we're targetting a non-NEON device.
+      dnl This matches media/webrtc/trunk/webrtc/build/common.gypi.
+      if test -n "$ARM_ARCH"; then
+          if test "$ARM_ARCH" -lt 7; then
+              BUILD_ARM_NEON=
+          else
+              AC_DEFINE(BUILD_ARM_NEON)
+              BUILD_ARM_NEON=1
+          fi
+      fi
+  fi
+
+fi # CPU_ARCH = arm
+
+AC_SUBST(HAVE_ARM_SIMD)
+AC_SUBST(HAVE_ARM_NEON)
+AC_SUBST(BUILD_ARM_NEON)
+AC_SUBST(ARM_ARCH)
+
+if test -n "$MOZ_ARCH"; then
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-arch=$MOZ_ARCH"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb=$MOZ_THUMB"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb-interwork=$MOZ_THUMB_INTERWORK"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-fpu=$MOZ_FPU"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-float-abi=$MOZ_FLOAT_ABI"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-soft-float=$MOZ_SOFT_FLOAT"
+fi
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4 b/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4
new file mode 100644
index 0000000..5618a1c
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4
@@ -0,0 +1,60 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_CONFIG_CLANG_PLUGIN], [
+
+MOZ_ARG_ENABLE_BOOL(clang-plugin,
+[  --enable-clang-plugin   Enable building with the mozilla clang plugin ],
+   ENABLE_CLANG_PLUGIN=1,
+   ENABLE_CLANG_PLUGIN= )
+if test -n "$ENABLE_CLANG_PLUGIN"; then
+    if test -z "$CLANG_CC"; then
+        AC_MSG_ERROR([Can't use clang plugin without clang.])
+    fi
+
+    AC_MSG_CHECKING([for llvm-config])
+    if test -z "$LLVMCONFIG"; then
+      LLVMCONFIG=`$CXX -print-prog-name=llvm-config`
+    fi
+
+    if test -z "$LLVMCONFIG"; then
+      LLVMCONFIG=`which llvm-config`
+    fi
+
+    if test ! -x "$LLVMCONFIG"; then
+      AC_MSG_RESULT([not found])
+      AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
+    fi
+
+    AC_MSG_RESULT([$LLVMCONFIG])
+
+    if test -z "$LLVMCONFIG"; then
+        AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
+    fi
+    LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags`
+    dnl The clang package we use on OSX is old, and its llvm-config doesn't
+    dnl recognize --system-libs, so ask for that separately.  llvm-config's
+    dnl failure here is benign, so we can ignore it if it happens.
+    LLVM_LDFLAGS=`$LLVMCONFIG --system-libs | xargs`
+    LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option | xargs`"
+
+    if test "${HOST_OS_ARCH}" = "Darwin"; then
+        CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization"
+        CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis"
+        CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex"
+        CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers"
+    else
+        CLANG_LDFLAGS="-lclangASTMatchers"
+    fi
+
+    AC_DEFINE(MOZ_CLANG_PLUGIN)
+fi
+
+AC_SUBST(LLVM_CXXFLAGS)
+AC_SUBST(LLVM_LDFLAGS)
+AC_SUBST(CLANG_LDFLAGS)
+
+AC_SUBST(ENABLE_CLANG_PLUGIN)
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/clean-config.sh b/src/third_party/mozjs-45/build/autoconf/clean-config.sh
new file mode 100755
index 0000000..2505547
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/clean-config.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# clean-config.sh - Removes all files generated by mozilla configure.
+#    Only removes files from the topsrcdir. To clean up an objdir,
+#    simply remove the directory and start over.
+#
+# Usage:
+#    1. cd <topsrcdir>
+#    2. build/autoconf/clean-config.sh
+#
+# Send comments, improvements, bugs to slamm@netscape.com
+
+topsrcdir=`cd \`dirname $0\`/../..; pwd`
+
+if [ ! -f configure.in ]; then
+  echo "clean-config.sh only cleans the source tree. To run," 2>&1
+  echo "  cd $topsrcdir; build/autoconf/clean-config.sh" 2>&1
+  echo "  (To clean a separate objdir, simple remove the directory.)" 2>&1
+  exit 1
+fi
+
+rm -fr \
+    config-defs.h \
+    config.cache \
+    config.log \
+    config.status \
+    $NULL
diff --git a/src/third_party/mozjs-45/build/autoconf/codeset.m4 b/src/third_party/mozjs-45/build/autoconf/codeset.m4
new file mode 100644
index 0000000..4dc1d50
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/codeset.m4
@@ -0,0 +1,24 @@
+# codeset.m4 serial AM1 (gettext-0.10.40)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+  AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
+    [AC_TRY_LINK([#include <langinfo.h>],
+      [char* cs = nl_langinfo(CODESET);],
+      am_cv_langinfo_codeset=yes,
+      am_cv_langinfo_codeset=no)
+    ])
+  if test $am_cv_langinfo_codeset = yes; then
+    AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
+      [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+      HAVE_LANGINFO_CODESET=1
+  fi
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4 b/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4
new file mode 100644
index 0000000..56d6af4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4
@@ -0,0 +1,425 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Add compiler specific options
+
+AC_DEFUN([MOZ_DEFAULT_COMPILER],
+[
+dnl set DEVELOPER_OPTIONS early; MOZ_DEFAULT_COMPILER is usually the first non-setup directive
+  if test -z "$MOZILLA_OFFICIAL"; then
+    DEVELOPER_OPTIONS=1
+  fi
+  MOZ_ARG_ENABLE_BOOL(release,
+  [  --enable-release        Build with more conservative, release engineering-oriented options.
+                          This may slow down builds.],
+      DEVELOPER_OPTIONS=,
+      DEVELOPER_OPTIONS=1)
+
+  AC_SUBST(DEVELOPER_OPTIONS)
+
+dnl Default to MSVC for win32 and gcc-4.2 for darwin
+dnl ==============================================================
+if test -z "$CROSS_COMPILE"; then
+case "$target" in
+*-mingw*)
+    if test -z "$CC"; then CC=cl; fi
+    if test -z "$CXX"; then CXX=cl; fi
+    if test -z "$CPP"; then CPP="$CC -E -nologo"; fi
+    if test -z "$CXXCPP"; then CXXCPP="$CXX -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
+    if test -z "$LD"; then LD=link; fi
+    if test -z "$AS"; then
+        case "${target_cpu}" in
+        i*86)
+            AS=ml;
+            ;;
+        x86_64)
+            AS=ml64;
+            ;;
+        esac
+    fi
+    if test -z "$MIDL"; then MIDL=midl; fi
+
+    # need override this flag since we don't use $(LDFLAGS) for this.
+    if test -z "$HOST_LDFLAGS" ; then
+        HOST_LDFLAGS=" "
+    fi
+    ;;
+*-darwin*)
+    # GCC on darwin is based on gcc 4.2 and we don't support it anymore.
+    if test -z "$CC"; then
+        MOZ_PATH_PROGS(CC, clang)
+    fi
+    if test -z "$CXX"; then
+        MOZ_PATH_PROGS(CXX, clang++)
+    fi
+    IS_GCC=$($CC -v 2>&1 | grep gcc)
+    if test -n "$IS_GCC"
+    then
+      echo gcc is known to be broken on OS X, please use clang.
+      echo see http://developer.mozilla.org/en-US/docs/Developer_Guide/Build_Instructions/Mac_OS_X_Prerequisites
+      echo for more information.
+      exit 1
+    fi
+    ;;
+esac
+fi
+])
+
+dnl ============================================================================
+dnl C++ rtti
+dnl We don't use it in the code, but it can be usefull for debugging, so give
+dnl the user the option of enabling it.
+dnl ============================================================================
+AC_DEFUN([MOZ_RTTI],
+[
+MOZ_ARG_ENABLE_BOOL(cpp-rtti,
+[  --enable-cpp-rtti       Enable C++ RTTI ],
+[ _MOZ_USE_RTTI=1 ],
+[ _MOZ_USE_RTTI= ])
+
+if test -z "$_MOZ_USE_RTTI"; then
+    if test "$GNU_CC"; then
+        CXXFLAGS="$CXXFLAGS -fno-rtti"
+    else
+        case "$target" in
+        *-mingw*)
+            CXXFLAGS="$CXXFLAGS -GR-"
+        esac
+    fi
+fi
+])
+
+dnl ========================================================
+dnl =
+dnl = Debugging Options
+dnl =
+dnl ========================================================
+AC_DEFUN([MOZ_DEBUGGING_OPTS],
+[
+dnl Debug info is ON by default.
+if test -z "$MOZ_DEBUG_FLAGS"; then
+  if test -n "$_MSC_VER"; then
+    MOZ_DEBUG_FLAGS="-Zi"
+  else
+    MOZ_DEBUG_FLAGS="-g"
+  fi
+fi
+
+AC_SUBST(MOZ_DEBUG_FLAGS)
+
+MOZ_ARG_ENABLE_STRING(debug,
+[  --enable-debug[=DBG]    Enable building with developer debug info
+                           (using compiler flags DBG)],
+[ if test "$enableval" != "no"; then
+    MOZ_DEBUG=1
+    if test -n "$enableval" -a "$enableval" != "yes"; then
+        MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'`
+        _MOZ_DEBUG_FLAGS_SET=1
+    fi
+  else
+    MOZ_DEBUG=
+  fi ],
+  MOZ_DEBUG=)
+
+if test -z "$MOZ_DEBUG" -o -n "$MOZ_ASAN"; then
+    MOZ_NO_DEBUG_RTL=1
+fi
+
+AC_SUBST(MOZ_NO_DEBUG_RTL)
+
+MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -DTRACING"
+MOZ_ARG_WITH_STRING(debug-label,
+[  --with-debug-label=LABELS
+                          Define DEBUG_<value> for each comma-separated
+                          value given.],
+[ for option in `echo $withval | sed 's/,/ /g'`; do
+    MOZ_DEBUG_ENABLE_DEFS="$MOZ_DEBUG_ENABLE_DEFS -DDEBUG_${option}"
+done])
+
+if test -n "$MOZ_DEBUG"; then
+    AC_MSG_CHECKING([for valid debug flags])
+    _SAVE_CFLAGS=$CFLAGS
+    CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS"
+    AC_TRY_COMPILE([#include <stdio.h>],
+        [printf("Hello World\n");],
+        _results=yes,
+        _results=no)
+    AC_MSG_RESULT([$_results])
+    if test "$_results" = "no"; then
+        AC_MSG_ERROR([These compiler flags are invalid: $MOZ_DEBUG_FLAGS])
+    fi
+    CFLAGS=$_SAVE_CFLAGS
+
+    MOZ_DEBUG_DEFINES="$MOZ_DEBUG_ENABLE_DEFS"
+else
+    MOZ_DEBUG_DEFINES="-DNDEBUG -DTRIMMED"
+fi
+
+AC_SUBST(MOZ_DEBUG_DEFINES)
+
+dnl ========================================================
+dnl = Enable generation of debug symbols
+dnl ========================================================
+MOZ_ARG_ENABLE_STRING(debug-symbols,
+[  --enable-debug-symbols[=DBG]
+                          Enable debugging symbols (using compiler flags DBG)],
+[ if test "$enableval" != "no"; then
+      MOZ_DEBUG_SYMBOLS=1
+      if test -n "$enableval" -a "$enableval" != "yes"; then
+          if test -z "$_MOZ_DEBUG_FLAGS_SET"; then
+              MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'`
+          else
+              AC_MSG_ERROR([--enable-debug-symbols flags cannot be used with --enable-debug flags])
+          fi
+      fi
+  else
+      MOZ_DEBUG_SYMBOLS=
+  fi ],
+  MOZ_DEBUG_SYMBOLS=1)
+
+if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then
+    AC_DEFINE(MOZ_DEBUG_SYMBOLS)
+    export MOZ_DEBUG_SYMBOLS
+fi
+
+])
+
+dnl A high level macro for selecting compiler options.
+AC_DEFUN([MOZ_COMPILER_OPTS],
+[
+  MOZ_DEBUGGING_OPTS
+  MOZ_RTTI
+if test "$CLANG_CXX"; then
+    ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
+    ## returned by C functions. This is possible because we use knowledge about the ABI
+    ## to typedef it to a C type with the same layout when the headers are included
+    ## from C.
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
+fi
+
+AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) actually is a C++ compiler])
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+_SAVE_LIBS=$LIBS
+LIBS=
+AC_TRY_LINK([#include <new>], [int *foo = new int;],,
+            AC_MSG_RESULT([no])
+            AC_MSG_ERROR([$CXX $CXXFLAGS $LDFLAGS failed to compile and link a simple C++ source.]))
+LIBS=$_SAVE_LIBS
+AC_LANG_RESTORE
+AC_MSG_RESULT([yes])
+
+if test -n "$DEVELOPER_OPTIONS"; then
+    MOZ_FORCE_GOLD=1
+fi
+
+MOZ_ARG_ENABLE_BOOL(gold,
+[  --enable-gold           Enable GNU Gold Linker when it is not already the default],
+    MOZ_FORCE_GOLD=1,
+    MOZ_FORCE_GOLD=
+    )
+
+if test "$GNU_CC" -a -n "$MOZ_FORCE_GOLD"; then
+    dnl if the default linker is BFD ld, check if gold is available and try to use it
+    dnl for local builds only.
+    if $CC -Wl,--version 2>&1 | grep -q "GNU ld"; then
+        GOLD=$($CC -print-prog-name=ld.gold)
+        case "$GOLD" in
+        /*)
+            ;;
+        *)
+            GOLD=$(which $GOLD)
+            ;;
+        esac
+        if test -n "$GOLD"; then
+            mkdir -p $_objdir/build/unix/gold
+            rm -f $_objdir/build/unix/gold/ld
+            ln -s "$GOLD" $_objdir/build/unix/gold/ld
+            if $CC -B $_objdir/build/unix/gold -Wl,--version 2>&1 | grep -q "GNU gold"; then
+                LDFLAGS="$LDFLAGS -B $_objdir/build/unix/gold"
+            else
+                rm -rf $_objdir/build/unix/gold
+            fi
+        fi
+    fi
+fi
+if test "$GNU_CC"; then
+    if $CC $LDFLAGS -Wl,--version 2>&1 | grep -q "GNU ld"; then
+        LD_IS_BFD=1
+    fi
+fi
+
+AC_SUBST([LD_IS_BFD])
+
+if test "$GNU_CC"; then
+    if test -z "$DEVELOPER_OPTIONS"; then
+        CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
+        CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
+    fi
+    CFLAGS="$CFLAGS -fno-math-errno"
+    CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-math-errno"
+fi
+
+dnl ========================================================
+dnl = Identical Code Folding
+dnl ========================================================
+
+MOZ_ARG_DISABLE_BOOL(icf,
+[  --disable-icf          Disable Identical Code Folding],
+    MOZ_DISABLE_ICF=1,
+    MOZ_DISABLE_ICF= )
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF" -a -z "$DEVELOPER_OPTIONS"; then
+    AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
+        LD_SUPPORTS_ICF,
+        [echo 'int foo() {return 42;}' \
+              'int bar() {return 42;}' \
+              'int main() {return foo() - bar();}' > conftest.${ac_ext}
+        # If the linker supports ICF, foo and bar symbols will have
+        # the same address
+        if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
+           test -s conftest${ac_exeext} &&
+           objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
+            LD_SUPPORTS_ICF=yes
+        else
+            LD_SUPPORTS_ICF=no
+        fi
+        rm -rf conftest*])
+    if test "$LD_SUPPORTS_ICF" = yes; then
+        _SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
+        LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
+        AC_TRY_LINK([], [],
+                    [LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
+                    [LD_PRINT_ICF_SECTIONS=])
+        AC_SUBST([LD_PRINT_ICF_SECTIONS])
+        LDFLAGS="$_SAVE_LDFLAGS"
+    fi
+fi
+
+dnl ========================================================
+dnl = Automatically remove dead symbols
+dnl ========================================================
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS"; then
+    if test -n "$MOZ_DEBUG_FLAGS"; then
+        dnl See bug 670659
+        AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
+            GC_SECTIONS_BREAKS_DEBUG_RANGES,
+            [echo 'int foo() {return 42;}' \
+                  'int bar() {return 1;}' \
+                  'int main() {return foo();}' > conftest.${ac_ext}
+            if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
+                AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
+                test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
+                 if test "`$PYTHON -m mozbuild.configure.check_debug_ranges conftest.${ac_objext} conftest.${ac_ext}`" = \
+                         "`$PYTHON -m mozbuild.configure.check_debug_ranges conftest${ac_exeext} conftest.${ac_ext}`"; then
+                     GC_SECTIONS_BREAKS_DEBUG_RANGES=no
+                 else
+                     GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
+                 fi
+             else
+                  dnl We really don't expect to get here, but just in case
+                  GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
+             fi
+             rm -rf conftest*])
+         if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
+             DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+         fi
+    else
+        DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+    fi
+fi
+
+# bionic in Android < 4.1 doesn't support PIE
+# On OSX, the linker defaults to building PIE programs when targetting OSX 10.7+,
+# but not when targetting OSX < 10.7. OSX < 10.7 doesn't support running PIE
+# programs, so as long as support for OSX 10.6 is kept, we can't build PIE.
+# Even after dropping 10.6 support, MOZ_PIE would not be useful since it's the
+# default (and clang says the -pie option is not used).
+# On other Unix systems, some file managers (Nautilus) can't start PIE programs
+if test -n "$gonkdir" && test "$ANDROID_VERSION" -ge 16; then
+    MOZ_PIE=1
+else
+    MOZ_PIE=
+fi
+
+MOZ_ARG_ENABLE_BOOL(pie,
+[  --enable-pie           Enable Position Independent Executables],
+    MOZ_PIE=1,
+    MOZ_PIE= )
+
+if test "$GNU_CC" -a -n "$MOZ_PIE"; then
+    AC_MSG_CHECKING([for PIE support])
+    _SAVE_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS -pie"
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+                  [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
+                  AC_MSG_RESULT([no])
+                  AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
+    LDFLAGS=$_SAVE_LDFLAGS
+fi
+
+AC_SUBST(MOZ_PROGRAM_LDFLAGS)
+
+dnl ASan assumes no symbols are being interposed, and when that happens,
+dnl it's not happy with it. Unconveniently, since Firefox is exporting
+dnl libffi symbols and Gtk+3 pulls system libffi via libwayland-client,
+dnl system libffi interposes libffi symbols that ASan assumes are in
+dnl libxul, so it barfs about buffer overflows.
+dnl Using -Wl,-Bsymbolic ensures no exported symbol can be interposed.
+if test -n "$GCC_USE_GNU_LD"; then
+  case "$LDFLAGS" in
+  *-fsanitize=address*)
+    LDFLAGS="$LDFLAGS -Wl,-Bsymbolic"
+    ;;
+  esac
+fi
+
+])
+
+dnl GCC and clang will fail if given an unknown warning option like -Wfoobar. 
+dnl But later versions won't fail if given an unknown negated warning option
+dnl like -Wno-foobar.  So when we are check for support of negated warning 
+dnl options, we actually test the positive form, but add the negated form to 
+dnl the flags variable.
+
+AC_DEFUN([MOZ_C_SUPPORTS_WARNING],
+[
+    AC_CACHE_CHECK(whether the C compiler supports $1$2, $3,
+        [
+            AC_LANG_SAVE
+            AC_LANG_C
+            _SAVE_CFLAGS="$CFLAGS"
+            CFLAGS="$CFLAGS -Werror -W$2"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           $3="yes",
+                           $3="no")
+            CFLAGS="$_SAVE_CFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "${$3}" = "yes"; then
+        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} $1$2"
+    fi
+])
+
+AC_DEFUN([MOZ_CXX_SUPPORTS_WARNING],
+[
+    AC_CACHE_CHECK(whether the C++ compiler supports $1$2, $3,
+        [
+            AC_LANG_SAVE
+            AC_LANG_CPLUSPLUS
+            _SAVE_CXXFLAGS="$CXXFLAGS"
+            CXXFLAGS="$CXXFLAGS -Werror -W$2"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           $3="yes",
+                           $3="no")
+            CXXFLAGS="$_SAVE_CXXFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "${$3}" = "yes"; then
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} $1$2"
+    fi
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/config.guess b/src/third_party/mozjs-45/build/autoconf/config.guess
new file mode 100755
index 0000000..72625d4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/config.guess
@@ -0,0 +1,1420 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-02-12'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    or1k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx<