Import Cobalt 11.61806
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
index 6d04858..4b2f4da 100644
--- a/src/base/atomicops.h
+++ b/src/base/atomicops.h
@@ -35,15 +35,6 @@
 #include "starboard/atomic.h"
 #endif  // defined(OS_STARBOARD)
 
-#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || defined(__LB_XB360__) || defined(__LB_XB1__)
-// windows.h #defines this (only on x64). This causes problems because the
-// public API also uses MemoryBarrier at the public name for this fence. So, on
-// X64, undef it, and call its documented
-// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
-// implementation directly.
-#undef MemoryBarrier
-#endif
-
 namespace base {
 namespace subtle {
 
diff --git a/src/base/file_path.h b/src/base/file_path.h
index d1eb74c..14c2340 100644
--- a/src/base/file_path.h
+++ b/src/base/file_path.h
@@ -113,15 +113,6 @@
 #include "base/string_piece.h"  // For implicit conversions.
 #include "build/build_config.h"
 
-// Windows-style drive letter support and pathname separator characters can be
-// enabled and disabled independently, to aid testing.  These #defines are
-// here so that the same setting can be used in both the implementation and
-// in the unit test.
-#if defined(OS_WIN) || defined(__LB_XB1__) || defined(__LB_XB360__)
-#define FILE_PATH_USES_DRIVE_LETTERS
-#define FILE_PATH_USES_WIN_SEPARATORS
-#endif  // OS_WIN || __LB_XB1__ || __LB_XB360__
-
 class Pickle;
 class PickleIterator;
 
diff --git a/src/base/file_util_unittest.cc b/src/base/file_util_unittest.cc
index 66595fc..847a1e0 100644
--- a/src/base/file_util_unittest.cc
+++ b/src/base/file_util_unittest.cc
@@ -1957,7 +1957,7 @@
   EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
   EXPECT_EQ(c2_non_recursive.size(), 2);
 
-#if !defined(__LB_XB1__) && !defined(OS_STARBOARD)
+#if !defined(OS_STARBOARD)
 // As all file access is absolute, this is not an issue
   // Only enumerate directories, non-recursively, including "..".
   file_util::FileEnumerator f2_dotdot(temp_dir_.path(), false,
diff --git a/src/base/format_macros.h b/src/base/format_macros.h
index a073b83..b3f6506 100644
--- a/src/base/format_macros.h
+++ b/src/base/format_macros.h
@@ -50,7 +50,8 @@
 #define PRIuS "zu"
 #endif
 
-#else  // OS_WIN || __LB_XB1__ || __LB_XB360__
+#else  // (defined(OS_POSIX) || defined(OS_STARBOARD)) &&
+       // !defined(COMPILER_MSVC)
 
 #if !defined(PRId64)
 #define PRId64 "I64d"
diff --git a/src/base/logging.cc b/src/base/logging.cc
index d3a97e5..bc2356e 100644
--- a/src/base/logging.cc
+++ b/src/base/logging.cc
@@ -77,12 +77,6 @@
 #include <android/log.h>
 #endif
 
-#if defined(__LB_XB1__) || defined(__LB_XB360__)
-#undef MAX_PATH
-#include <Windows.h>
-#undef MAX_PATH
-#endif
-
 namespace logging {
 
 DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
diff --git a/src/base/stringprintf.cc b/src/base/stringprintf.cc
index 76a6dbd..d4576d0 100644
--- a/src/base/stringprintf.cc
+++ b/src/base/stringprintf.cc
@@ -72,10 +72,7 @@
   int mem_length = arraysize(stack_buf);
   while (true) {
     if (result < 0) {
-#if defined(__LB_XB1__) || defined(__LB_XB360__)
-      // On XB1, we get a -1 with ERANGE when the buffer is not big enough.
-      if (result != -1 || (errno != 0 && errno != ERANGE))
-#elif !defined(OS_WIN)
+#if !defined(OS_WIN)
       // On Windows, vsnprintfT always returns the number of characters in a
       // fully-formatted string, so if we reach this point, something else is
       // wrong and no amount of buffer-doubling is going to fix it.
diff --git a/src/base/stringprintf_unittest.cc b/src/base/stringprintf_unittest.cc
index 143fc42..6d83a6d 100644
--- a/src/base/stringprintf_unittest.cc
+++ b/src/base/stringprintf_unittest.cc
@@ -162,21 +162,6 @@
   EXPECT_STREQ(src, out.c_str());
 }
 
-// TODO(evanm): what's the proper cross-platform test here?
-#if defined(OS_WIN) || defined(__LB_XB1__) || defined(__LB_XB360__)
-// sprintf in Visual Studio fails when given U+FFFF. This tests that the
-// failure case is gracefuly handled.
-TEST(StringPrintfTest, Invalid) {
-  wchar_t invalid[2];
-  invalid[0] = 0xffff;
-  invalid[1] = 0;
-
-  std::wstring out;
-  SStringPrintf(&out, L"%ls", invalid);
-  EXPECT_STREQ(L"", out.c_str());
-}
-#endif
-
 // lbshell platforms do not support positional parameters,
 // and lbshell does not use the few parts of chromium that
 // leverage positional parameter support in the OS.
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index fb7ef5e..938907a 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -106,6 +106,8 @@
         'COBALT_JS_GARBAGE_COLLECTION_THRESHOLD_IN_BYTES=<(mozjs_garbage_collection_threshold_in_bytes)',
         'COBALT_MAX_CPU_USAGE_IN_BYTES=<(max_cobalt_cpu_usage)',
         'COBALT_MAX_GPU_USAGE_IN_BYTES=<(max_cobalt_gpu_usage)',
+        'COBALT_REDUCE_CPU_MEMORY_BY=<(reduce_cpu_memory_by)',
+        'COBALT_REDUCE_GPU_MEMORY_BY=<(reduce_gpu_memory_by)',
       ],
       'dependencies': [
         '<@(cobalt_platform_dependencies)',
diff --git a/src/cobalt/browser/memory_settings/auto_mem.cc b/src/cobalt/browser/memory_settings/auto_mem.cc
index 582c49e..f17ec05 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem.cc
@@ -17,6 +17,7 @@
 #include "cobalt/browser/memory_settings/auto_mem.h"
 
 #include <algorithm>
+#include <cmath>
 #include <string>
 #include <vector>
 
@@ -33,6 +34,7 @@
 #include "cobalt/browser/memory_settings/pretty_print.h"
 #include "cobalt/browser/memory_settings/scaling_function.h"
 #include "cobalt/browser/switches.h"
+#include "cobalt/math/clamp.h"
 #include "nb/lexical_cast.h"
 
 namespace cobalt {
@@ -230,15 +232,65 @@
          "monotonically decreasing values as input goes from 1.0 -> 0.0";
 }
 
+int64_t GenerateTargetMemoryBytes(
+    int64_t max_memory_bytes,
+    int64_t current_memory_bytes,
+    base::optional<int64_t> reduce_memory_bytes) {
+
+  // Make sure values are sanitized.
+  max_memory_bytes = std::max<int64_t>(0, max_memory_bytes);
+  current_memory_bytes = std::max<int64_t>(0, current_memory_bytes);
+
+  // If reduce_memory_bytes is valid and it's a zero or positive value then
+  // this is a signal that the calculation should be based off of this setting.
+  bool use_reduce_memory_input =
+      (reduce_memory_bytes && (-1 < *reduce_memory_bytes));
+
+  if (use_reduce_memory_input) {
+    // If reducing_memory_bytes is set exactly to 0, then this
+    // this will disable max_memory_bytes setting. current_memory_bytes
+    // will be returned as the target memory consumption,
+    // which will prevent memory constraining.
+    if (*reduce_memory_bytes == 0) {
+      return current_memory_bytes;
+    } else {
+      // Reduce memory bytes will subtract from the current memory
+      // consumption.
+      const int64_t target_value = current_memory_bytes - *reduce_memory_bytes;
+      return math::Clamp<int64_t>(target_value, 0, std::abs(target_value));
+    }
+  } else {  // reduce_memory_bytes is not used. Use max_memory_bytes instead.
+    // max_memory_bytes == 0 is special, and signals that no constraining
+    // should happen.
+    if (max_memory_bytes == 0) {
+      return current_memory_bytes;
+    } else {
+      // A non-zero value means that max_memory_bytes is valid and should
+      // be used as the target value.
+      return max_memory_bytes;
+    }
+  }
+}
+
 }  // namespace
 
 AutoMem::AutoMem(const math::Size& ui_resolution,
                  const CommandLine& command_line,
                  const BuildSettings& build_settings) {
   ConstructSettings(ui_resolution, command_line, build_settings);
+
+  const int64_t target_cpu_memory =
+      GenerateTargetMemoryBytes(max_cpu_bytes_->value(),
+                                SumAllMemoryOfType(MemorySetting::kCPU),
+                                reduced_cpu_bytes_->optional_value());
+  const int64_t target_gpu_memory =
+      GenerateTargetMemoryBytes(max_gpu_bytes_->value(),
+                                SumAllMemoryOfType(MemorySetting::kGPU),
+                                reduced_gpu_bytes_->optional_value());
+
   std::vector<MemorySetting*> memory_settings = AllMemorySettingsMutable();
-  ConstrainToMemoryLimits(max_cpu_bytes_->value(),
-                          max_gpu_bytes_->optional_value(),
+  ConstrainToMemoryLimits(target_cpu_memory,
+                          target_gpu_memory,
                           &memory_settings,
                           &error_msgs_);
 }
@@ -336,10 +388,14 @@
     error_msgs.push_back("ERROR - CPU CONSUMED WAS MORE THAN AVAILABLE.");
   }
 
-  if (max_gpu_bytes_->value() <= 0) {
-    error_msgs.push_back("ERROR - max_cobalt_gpu_usage WAS 0 BYTES.");
-  } else if (gpu_consumption > max_gpu_bytes_->value()) {
-    error_msgs.push_back("ERROR - GPU CONSUMED WAS MORE THAN AVAILABLE.");
+  const base::optional<int64_t> max_gpu_value =
+      max_gpu_bytes_->optional_value();
+  if (max_gpu_value) {
+    if (*max_gpu_value <= 0) {
+      error_msgs.push_back("ERROR - max_cobalt_gpu_usage WAS 0 BYTES.");
+    } else if (gpu_consumption > *max_gpu_value) {
+      error_msgs.push_back("ERROR - GPU CONSUMED WAS MORE THAN AVAILABLE.");
+    }
   }
 
   // Stringify error messages.
@@ -347,9 +403,9 @@
     std::stringstream ss_error;
     ss_error << "AutoMem had errors:\n";
     for (size_t i = 0; i < error_msgs.size(); ++i) {
-      ss_error << "   " << error_msgs[i] << "\n";
+      ss_error << "   " << error_msgs[i] << "\n\n";
     }
-    ss_error << "\nPlease see cobalt/docs/memory_tuning.md "
+    ss_error << "Please see cobalt/docs/memory_tuning.md "
                 "for more information.";
     ss << MakeBorder(ss_error.str(), '*');
   }
@@ -358,6 +414,11 @@
   return output_str;
 }
 
+int64_t AutoMem::SumAllMemoryOfType(
+    MemorySetting::MemoryType memory_type) const {
+  return SumMemoryConsumption(memory_type, AllMemorySettings());
+}
+
 void AutoMem::ConstructSettings(
     const math::Size& ui_resolution,
     const CommandLine& command_line,
@@ -365,6 +426,28 @@
   max_cpu_bytes_ = CreateCpuSetting(command_line, build_settings);
   max_gpu_bytes_ = CreateGpuSetting(command_line, build_settings);
 
+  reduced_cpu_bytes_ = CreateSystemMemorySetting(
+      switches::kReduceCpuMemoryBy,
+      MemorySetting::kCPU,
+      command_line,
+      build_settings.reduce_cpu_memory_by,
+      -1);
+  if (reduced_cpu_bytes_->value() == -1) {
+    // This effectively disables the value from being used in the constrainer.
+    reduced_cpu_bytes_->set_value(MemorySetting::kUnset, 0);
+  }
+
+  reduced_gpu_bytes_ = CreateSystemMemorySetting(
+      switches::kReduceGpuMemoryBy,
+      MemorySetting::kGPU,
+      command_line,
+      build_settings.reduce_gpu_memory_by,
+      -1);
+  if (reduced_cpu_bytes_->value() == -1) {
+    // This effectively disables the value from being used in the constrainer.
+    reduced_gpu_bytes_->set_value(MemorySetting::kUnset, 0);
+  }
+
   // Set the ImageCache
   image_cache_size_in_bytes_ = CreateMemorySetting<IntSetting, int64_t>(
       switches::kImageCacheSizeInBytes,
diff --git a/src/cobalt/browser/memory_settings/auto_mem.h b/src/cobalt/browser/memory_settings/auto_mem.h
index c018aec..66101e4 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.h
+++ b/src/cobalt/browser/memory_settings/auto_mem.h
@@ -65,6 +65,10 @@
   // information.
   std::string ToPrettyPrintString(bool use_color_ascii) const;
 
+  // Reports the total memory that all settings that match memory_type
+  // consume.
+  int64_t SumAllMemoryOfType(MemorySetting::MemoryType memory_type) const;
+
  private:
   void ConstructSettings(const math::Size& ui_resolution,
                          const CommandLine& command_line,
@@ -74,6 +78,7 @@
   std::vector<const MemorySetting*> AllMemorySettings() const;
   std::vector<MemorySetting*> AllMemorySettingsMutable();
 
+  // All of the following are included in AllMemorySettings().
   scoped_ptr<IntSetting> image_cache_size_in_bytes_;
   scoped_ptr<IntSetting> javascript_gc_threshold_in_bytes_;
   scoped_ptr<IntSetting> misc_cobalt_cpu_size_in_bytes_;
@@ -83,14 +88,21 @@
   scoped_ptr<IntSetting> skia_cache_size_in_bytes_;
   scoped_ptr<IntSetting> software_surface_cache_size_in_bytes_;
 
-  // These settings are used for constraining the memory.
+  // These settings are used for constraining the memory and are NOT included
+  // in AllMemorySettings().
   scoped_ptr<IntSetting> max_cpu_bytes_;
   scoped_ptr<IntSetting> max_gpu_bytes_;
+  scoped_ptr<IntSetting> reduced_cpu_bytes_;  // Forces CPU memory reduction.
+  scoped_ptr<IntSetting> reduced_gpu_bytes_;  // Forces GPU memory reduction.
+
   std::vector<std::string> error_msgs_;
 
   FRIEND_TEST(AutoMem, AllMemorySettingsAreOrderedByName);
   FRIEND_TEST(AutoMem, ConstrainedCPUEnvironment);
   FRIEND_TEST(AutoMem, ConstrainedGPUEnvironment);
+  FRIEND_TEST(AutoMem, ExplicitReducedCPUMemoryConsumption);
+  FRIEND_TEST(AutoMem, ExplicitReducedGPUMemoryConsumption);
+  FRIEND_TEST(AutoMem, MaxCpuIsIgnoredDuringExplicitMemoryReduction);
 };
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/auto_mem_test.cc b/src/cobalt/browser/memory_settings/auto_mem_test.cc
index 5a17825..1e289e7 100644
--- a/src/cobalt/browser/memory_settings/auto_mem_test.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem_test.cc
@@ -30,9 +30,16 @@
 namespace cobalt {
 namespace browser {
 namespace memory_settings {
+namespace {
 
 const math::Size kResolution1080p(1920, 1080);
 
+// Represents what the cobalt engine can scale down to under a default
+// environment.
+const int64_t kSmallEngineCpuMemorySize = 130 * 1024 * 1024;
+
+const int64_t kSmallEngineGpuMemorySize = 68 * 1024 * 1024;
+
 #define EXPECT_MEMORY_SETTING(SETTING, SOURCE, MEMORY_TYPE, VALUE)          \
   EXPECT_EQ(VALUE, SETTING->value()) << " failure for " << SETTING->name(); \
   EXPECT_EQ(MEMORY_TYPE, SETTING->memory_type()) << "failure for "          \
@@ -40,6 +47,15 @@
   EXPECT_EQ(SOURCE, SETTING->source_type()) << " failure for "              \
                                             << SETTING->name();
 
+scoped_ptr<AutoMem> CreateDefaultAutoMem() {
+  CommandLine empty_command_line(CommandLine::NO_PROGRAM);
+  BuildSettings build_settings;
+  scoped_ptr<AutoMem> auto_mem(
+      new AutoMem(kResolution1080p, empty_command_line, build_settings));
+  return auto_mem.Pass();
+}
+}  // namespace.
+
 // Tests the expectation that the command-line overrides will be applied.
 // Settings which are enabled/disabled when blitter is enabled/disabled are
 // also tested.
@@ -56,10 +72,10 @@
                                  "4567");
 
   for (int i = 0; i <= 1; ++i) {
-    BuildSettings builtin_settings = GetDefaultBuildSettings();
-    builtin_settings.has_blitter = (i == 0);
+    BuildSettings build_settings = GetDefaultBuildSettings();
+    build_settings.has_blitter = (i == 0);
 
-    AutoMem auto_mem(kResolution1080p, command_line, builtin_settings);
+    AutoMem auto_mem(kResolution1080p, command_line, build_settings);
 
     // image_cache_size_in_bytes and javascript_gc_threshold_in_bytes settings
     // ignore the blitter type.
@@ -71,7 +87,7 @@
 
     // Certain features are only available for the blitter, and some features
     // are disabled, vice versa.
-    if (builtin_settings.has_blitter) {
+    if (build_settings.has_blitter) {
       // When blitter is active then skia_atlas_texture_dimensions are
       // not applicable because this is an OpenGl egl feature.
       EXPECT_MEMORY_SETTING(
@@ -123,15 +139,15 @@
 // been set.
 TEST(AutoMem, SkiaGlyphAtlasTextureSize) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
-  BuildSettings builtin_settings_with_default;
+  BuildSettings build_settings;
+  BuildSettings build_settings_with_default;
 
-  builtin_settings_with_default.skia_texture_atlas_dimensions =
+  build_settings_with_default.skia_texture_atlas_dimensions =
       TextureDimensions(1234, 5678, 2);
 
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
   AutoMem auto_mem_with_default(kResolution1080p, empty_command_line,
-                                builtin_settings_with_default);
+                                build_settings_with_default);
 
   // Expect that when the skia_atlas_texture_dimensions is specified in the
   // build settings that it will bind to the auto-set value (computed from
@@ -151,16 +167,16 @@
 // it has been set.
 TEST(AutoMem, SoftwareSurfaceCacheSizeInBytes) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
-  BuildSettings builtin_settings_with_default;
+  BuildSettings build_settings;
+  BuildSettings build_settings_with_default;
   // Enable the setting by enabling the blitter.
-  builtin_settings.has_blitter = true;
-  builtin_settings_with_default.has_blitter = true;
-  builtin_settings_with_default.software_surface_cache_size_in_bytes = 1234;
+  build_settings.has_blitter = true;
+  build_settings_with_default.has_blitter = true;
+  build_settings_with_default.software_surface_cache_size_in_bytes = 1234;
 
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
   AutoMem auto_mem_with_surface_cache(kResolution1080p, empty_command_line,
-                                      builtin_settings_with_default);
+                                      build_settings_with_default);
 
   // Expect that when the software_surface_cache_size_in_bytes is specified in
   // the/ build settings that it will bind to the auto-set value (computed from
@@ -179,13 +195,13 @@
 // it has been set.
 TEST(AutoMem, SkiaCacheSizeInBytes) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
-  BuildSettings builtin_settings_with_default;
-  builtin_settings_with_default.skia_cache_size_in_bytes = 1234;
+  BuildSettings build_settings;
+  BuildSettings build_settings_with_default;
+  build_settings_with_default.skia_cache_size_in_bytes = 1234;
 
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
   AutoMem auto_mem_with_skia_cache(kResolution1080p, empty_command_line,
-                                   builtin_settings_with_default);
+                                   build_settings_with_default);
 
   EXPECT_MEMORY_SETTING(auto_mem.skia_cache_size_in_bytes(),
                         MemorySetting::kAutoSet, MemorySetting::kGPU,
@@ -198,9 +214,9 @@
 
 TEST(AutoMem, AllMemorySettingsAreOrderedByName) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
+  BuildSettings build_settings;
 
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
 
   std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
 
@@ -209,30 +225,27 @@
   }
 }
 
-// Tests the expectation that constraining the CPU memory to 130MB will result
-// in AutoMem reducing the the memory footprint.
+// Tests the expectation that constraining the CPU memory to kSmallEngineSize
+// will result in AutoMem reducing to the expected memory footprint.
 TEST(AutoMem, ConstrainedCPUEnvironment) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
-  builtin_settings.max_cpu_in_bytes = 130 * 1024 * 1024;
+  BuildSettings build_settings;
+  build_settings.max_cpu_in_bytes = kSmallEngineCpuMemorySize;
 
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
-
-  std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
 
   const int64_t cpu_memory_consumption =
-      SumMemoryConsumption(MemorySetting::kCPU, settings);
-
-  EXPECT_LE(cpu_memory_consumption, 130 * 1024 * 1024);
+      auto_mem.SumAllMemoryOfType(MemorySetting::kCPU);
+  EXPECT_LE(cpu_memory_consumption, kSmallEngineCpuMemorySize);
 }
 
 // Tests the expectation that constraining the CPU memory to 40MB will result
 // in AutoMem reducing the the memory footprint.
 TEST(AutoMem, ConstrainedGPUEnvironment) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
-  BuildSettings builtin_settings;
-  builtin_settings.max_gpu_in_bytes = 57 * 1024 * 1024;
-  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+  BuildSettings build_settings;
+  build_settings.max_gpu_in_bytes = 57 * 1024 * 1024;
+  AutoMem auto_mem(kResolution1080p, empty_command_line, build_settings);
 
   std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
   const int64_t gpu_memory_consumption =
@@ -240,6 +253,183 @@
   EXPECT_LE(gpu_memory_consumption, 57 * 1024 * 1024);
 }
 
+// Tests the expectation that constraining the CPU memory to 40MB will result
+// in AutoMem reducing the the memory footprint.
+TEST(AutoMem, ExplicitReducedCPUMemoryConsumption) {
+  // STEP ONE: Get the "natural" size of the engine at the default test
+  // settings.
+  scoped_ptr<AutoMem> default_auto_mem = CreateDefaultAutoMem();
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kReduceCpuMemoryBy, "5MB");
+  BuildSettings build_settings;
+  AutoMem reduced_cpu_memory_auto_mem(kResolution1080p, command_line,
+                                      build_settings);
+
+  EXPECT_EQ(5*1024*1024,
+            reduced_cpu_memory_auto_mem.reduced_cpu_bytes_->value());
+
+  const int64_t original_memory_consumption =
+      default_auto_mem->SumAllMemoryOfType(MemorySetting::kCPU);
+  const int64_t reduced_memory_consumption =
+      reduced_cpu_memory_auto_mem.SumAllMemoryOfType(MemorySetting::kCPU);
+
+  EXPECT_LE(5*1024*1024,
+            original_memory_consumption - reduced_memory_consumption);
+}
+
+// Tests the expectation that constraining the CPU memory to 40MB will result
+// in AutoMem reducing the the memory footprint.
+TEST(AutoMem, ExplicitReducedGPUMemoryConsumption) {
+  // STEP ONE: Get the "natural" size of the engine at the default test
+  // settings.
+  scoped_ptr<AutoMem> default_auto_mem = CreateDefaultAutoMem();
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kReduceGpuMemoryBy, "5MB");
+  BuildSettings build_settings;
+  AutoMem reduced_cpu_memory_auto_mem(kResolution1080p, command_line,
+                                      build_settings);
+  EXPECT_EQ(5*1024*1024,
+            reduced_cpu_memory_auto_mem.reduced_gpu_bytes_->value());
+
+  const int64_t original_memory_consumption =
+      default_auto_mem->SumAllMemoryOfType(MemorySetting::kGPU);
+  const int64_t reduced_memory_consumption =
+      reduced_cpu_memory_auto_mem.SumAllMemoryOfType(MemorySetting::kGPU);
+
+  EXPECT_LE(5*1024*1024,
+            original_memory_consumption - reduced_memory_consumption);
+}
+
+// Tests the expectation that the max cpu value is ignored when reducing
+// memory.
+TEST(AutoMem, MaxCpuIsIgnoredDuringExplicitMemoryReduction) {
+  // STEP ONE: Get the "natural" size of the engine at the default test
+  // settings.
+  scoped_ptr<AutoMem> default_auto_mem = CreateDefaultAutoMem();
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kReduceCpuMemoryBy, "5MB");
+  BuildSettings build_settings;
+  build_settings.max_cpu_in_bytes = 1;
+  AutoMem reduced_cpu_memory_auto_mem(kResolution1080p, command_line,
+                                      build_settings);
+
+  EXPECT_EQ(5*1024*1024,
+            reduced_cpu_memory_auto_mem.reduced_cpu_bytes_->value());
+
+  const int64_t original_memory_consumption =
+      default_auto_mem->SumAllMemoryOfType(MemorySetting::kCPU);
+  const int64_t reduced_memory_consumption =
+      reduced_cpu_memory_auto_mem.SumAllMemoryOfType(MemorySetting::kCPU);
+
+  // Max_cpu_in_bytes specifies one byte of memory, but reduce must override
+  // this for this test to pass.
+  EXPECT_LE(5*1024*1024,
+            original_memory_consumption - reduced_memory_consumption);
+}
+
+// Tests the expectation that the constrainer will not run on cpu memory if
+// --reduce_cpu_memory_by is set to 0.
+TEST(AutoMem, MaxCpuIsIgnoredWithZeroValueReduceCPUCommand) {
+  // STEP ONE: Get the "natural" size of the engine at the default test
+  // settings.
+  scoped_ptr<AutoMem> default_auto_mem = CreateDefaultAutoMem();
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  BuildSettings build_settings;
+
+  // Max memory is 1-byte. We expect that the kReduceCpuMemoryBy = "0" will
+  // override the max_cpu_in_bytes setting.
+  build_settings.max_cpu_in_bytes = 1;
+  command_line.AppendSwitchASCII(switches::kReduceCpuMemoryBy, "0");
+
+  AutoMem auto_mem_no_reduce_cpu(kResolution1080p, command_line,
+                                 build_settings);
+
+  const int64_t original_memory_consumption =
+      default_auto_mem->SumAllMemoryOfType(MemorySetting::kCPU);
+  const int64_t new_memory_consumption =
+      auto_mem_no_reduce_cpu.SumAllMemoryOfType(MemorySetting::kCPU);
+
+  // Max_cpu_in_bytes specifies one byte of memory, but reduce must override
+  // this for this test to pass.
+  EXPECT_EQ(original_memory_consumption, new_memory_consumption);
+}
+
+// Tests the expectation that the constrainer will not run on gpu memory if
+// --reduce_gpu_memory_by is set to 0.
+TEST(AutoMem, MaxCpuIsIgnoredWithZeroValueReduceGPUCommand) {
+  // STEP ONE: Get the "natural" size of the engine at the default test
+  // settings.
+  scoped_ptr<AutoMem> default_auto_mem = CreateDefaultAutoMem();
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  BuildSettings build_settings;
+
+  // Max memory is 1-byte. We expect that the kReduceCpuMemoryBy = "0" will
+  // override the max_cpu_in_bytes setting.
+  build_settings.max_gpu_in_bytes = 1;
+  command_line.AppendSwitchASCII(switches::kReduceGpuMemoryBy, "0");
+
+  AutoMem auto_mem_no_reduce_cpu(kResolution1080p, command_line,
+                                 build_settings);
+
+  const int64_t original_memory_consumption =
+      default_auto_mem->SumAllMemoryOfType(MemorySetting::kGPU);
+  const int64_t new_memory_consumption =
+      auto_mem_no_reduce_cpu.SumAllMemoryOfType(MemorySetting::kGPU);
+
+  // Max_gpu_in_bytes specifies one byte of memory, but reduce must override
+  // this for this test to pass.
+  EXPECT_EQ(original_memory_consumption, new_memory_consumption);
+}
+
+// Tests the expectation that if --reduce_cpu_memory_by is set to -1 that it
+// will be effectively disabled and --max_cpu_bytes be used as the memory
+// reduction means.
+TEST(AutoMem, MaxCpuIsEnabledWhenReduceCpuMemoryIsExplicitlyDisabled) {
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  BuildSettings build_settings;
+
+  // Max memory is 1-byte. We expect that the kReduceCpuMemoryBy = "-1"
+  // passed to the command line will cause max_cpu_in_bytes to be the
+  // dominating memory reduction mechanism.
+  build_settings.max_cpu_in_bytes = kSmallEngineGpuMemorySize;
+  command_line.AppendSwitchASCII(switches::kReduceCpuMemoryBy, "-1");
+
+  AutoMem auto_mem_no_reduce_cpu(kResolution1080p, command_line,
+                                 build_settings);
+  const int64_t memory_consumption =
+      auto_mem_no_reduce_cpu.SumAllMemoryOfType(MemorySetting::kCPU);
+  // Max_cpu_in_bytes specifies one byte of memory, but reduce must override
+  // this for this test to pass.
+  EXPECT_LE(memory_consumption, kSmallEngineCpuMemorySize);
+}
+
+// Tests the expectation that if --reduce_gpu_memory_by is set to -1 that it
+// will be effectively disabled and --max_gpu_bytes be used as the memory
+// reduction means.
+TEST(AutoMem, MaxGpuIsEnabledWhenReduceCpuMemoryIsExplicitlyDisabled) {
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  BuildSettings build_settings;
+
+  // Max memory is 1-byte. We expect that the kReduceCpuMemoryBy = "-1"
+  // passed to the command line will cause max_cpu_in_bytes to be the
+  // dominating memory reduction mechanism.
+  build_settings.max_cpu_in_bytes = kSmallEngineGpuMemorySize;
+  command_line.AppendSwitchASCII(switches::kReduceGpuMemoryBy, "-1");
+
+  AutoMem auto_mem_no_reduce_cpu(kResolution1080p, command_line,
+                                 build_settings);
+  const int64_t memory_consumption =
+      auto_mem_no_reduce_cpu.SumAllMemoryOfType(MemorySetting::kGPU);
+  // Max_cpu_in_bytes specifies one byte of memory, but reduce must override
+  // this for this test to pass.
+  EXPECT_LE(memory_consumption, kSmallEngineGpuMemorySize);
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/build_settings.cc b/src/cobalt/browser/memory_settings/build_settings.cc
index dcc75a3..1019eab 100644
--- a/src/cobalt/browser/memory_settings/build_settings.cc
+++ b/src/cobalt/browser/memory_settings/build_settings.cc
@@ -77,6 +77,12 @@
       MakeValidIfGreaterThanOrEqualToZero(COBALT_MAX_CPU_USAGE_IN_BYTES);
   settings.max_gpu_in_bytes =
       MakeValidIfGreaterThanOrEqualToZero(COBALT_MAX_GPU_USAGE_IN_BYTES);
+
+  settings.reduce_cpu_memory_by =
+      MakeValidIfGreaterThanOrEqualToZero(COBALT_REDUCE_CPU_MEMORY_BY);
+  settings.reduce_gpu_memory_by =
+      MakeValidIfGreaterThanOrEqualToZero(COBALT_REDUCE_GPU_MEMORY_BY);
+
   return settings;
 }
 
diff --git a/src/cobalt/browser/memory_settings/build_settings.h b/src/cobalt/browser/memory_settings/build_settings.h
index aff96ee..ea29197 100644
--- a/src/cobalt/browser/memory_settings/build_settings.h
+++ b/src/cobalt/browser/memory_settings/build_settings.h
@@ -38,6 +38,8 @@
 
   base::optional<int64_t> max_cpu_in_bytes;
   base::optional<int64_t> max_gpu_in_bytes;
+  base::optional<int64_t> reduce_cpu_memory_by;
+  base::optional<int64_t> reduce_gpu_memory_by;
 };
 
 BuildSettings GetDefaultBuildSettings();
diff --git a/src/cobalt/browser/memory_settings/constrainer.cc b/src/cobalt/browser/memory_settings/constrainer.cc
index f4a9e54..9e7a985 100644
--- a/src/cobalt/browser/memory_settings/constrainer.cc
+++ b/src/cobalt/browser/memory_settings/constrainer.cc
@@ -20,7 +20,9 @@
 #include <iterator>
 #include <vector>
 
+#include "base/logging.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
+#include "cobalt/browser/memory_settings/pretty_print.h"
 #include "starboard/configuration.h"
 
 namespace cobalt {
@@ -164,39 +166,62 @@
   }
 }
 
+void ConstrainMemoryType(MemorySetting::MemoryType memory_type,
+                         int64_t max_memory,
+                         std::vector<MemorySetting*>* memory_settings,
+                         std::vector<std::string>* error_msgs) {
+  if (max_memory == 0) {
+    return;
+  }
+  DCHECK_NE(MemorySetting::kNotApplicable, memory_type);
+  const char* memory_type_str = "UNKNOWN";
+  switch (memory_type) {
+    case MemorySetting::kCPU: { memory_type_str = "CPU"; break; }
+    case MemorySetting::kGPU: { memory_type_str = "GPU"; break; }
+    case MemorySetting::kNotApplicable: { memory_type_str = "ERROR"; break; }
+  }
+
+  std::vector<MemorySetting*> filtered_settings =
+      FilterSettings(memory_type, *memory_settings);
+
+  const int64_t current_consumption =
+      SumMemoryConsumption(memory_type, *memory_settings);
+
+  if (current_consumption < max_memory) {
+    return;
+  }
+
+  ConstrainToMemoryLimit(max_memory, &filtered_settings);
+
+  const int64_t new_memory_size = SumMemoryConsumption(memory_type,
+                                                       *memory_settings);
+
+  if (new_memory_size > max_memory) {
+    std::stringstream ss;
+    ss << "WARNING - ATTEMPTED TO CONSTRAIN " << memory_type_str
+       << " MEMORY FROM " << ToMegabyteString(current_consumption, 2)
+       << " TO " << ToMegabyteString(max_memory, 2) << ".\nBUT STOPPED"
+       << " AT " << ToMegabyteString(new_memory_size, 2) << " because"
+       << " there was nothing left to\n"
+       << "constrain (settings refused to reduce any more memory). Try\n"
+       << "setting more memory setting(s) to -1 to allow autoset.\n"
+       << "Example: --image_cache_size_in_bytes=-1";
+    error_msgs->push_back(ss.str());
+  }
+}
+
 }  // namespace.
 
-void ConstrainToMemoryLimits(
-    const int64_t& max_cpu_memory,
-    const base::optional<int64_t>& max_gpu_memory,
-    std::vector<MemorySetting*>* memory_settings,
-    std::vector<std::string>* error_msgs) {
-
-  // Some platforms may just return 0 for the max_cpu memory, in this case
-  // we don't want to constrain the memory.
-  if (max_cpu_memory > 0) {
-    std::vector<MemorySetting*> cpu_memory_settings =
-        FilterSettings(MemorySetting::kCPU, *memory_settings);
-    ConstrainToMemoryLimit(max_cpu_memory, &cpu_memory_settings);
-  } else {
-    error_msgs->push_back(
-        "ERROR - COULD NOT CONSTRAIN CPU MEMORY "
-        "BECAUSE max_cobalt_cpu_usage WAS 0.");
-  }
-
-  // Some platforms may just return 0 for the max_gpu memory, in this case
-  // we don't want to constrain the memory.
-  if (max_gpu_memory) {
-    if (*max_gpu_memory > 0) {
-      std::vector<MemorySetting*> gpu_memory_settings =
-          FilterSettings(MemorySetting::kGPU, *memory_settings);
-      ConstrainToMemoryLimit(*max_gpu_memory, &gpu_memory_settings);
-    } else {
-      error_msgs->push_back(
-          "ERROR - COULD NOT CONSTRAIN GPU MEMORY "
-          "BECAUSE max_cobalt_gpu_usage WAS 0.");
-    }
-  }
+void ConstrainToMemoryLimits(int64_t max_cpu_memory,
+                             int64_t max_gpu_memory,
+                             std::vector<MemorySetting*>* memory_settings,
+                             std::vector<std::string>* error_msgs) {
+  // Constrain cpu memory.
+  ConstrainMemoryType(MemorySetting::kCPU, max_cpu_memory,
+                      memory_settings, error_msgs);
+  // Constrain gpu memory.
+  ConstrainMemoryType(MemorySetting::kGPU, max_gpu_memory,
+                      memory_settings, error_msgs);
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/constrainer.h b/src/cobalt/browser/memory_settings/constrainer.h
index 3c22193..64b9e94 100644
--- a/src/cobalt/browser/memory_settings/constrainer.h
+++ b/src/cobalt/browser/memory_settings/constrainer.h
@@ -38,12 +38,10 @@
 //
 // The output variable error_msgs will be populated with any error messages
 // that result from this function call.
-void ConstrainToMemoryLimits(
-    const int64_t& max_cpu_memory,
-    const base::optional<int64_t>& max_gpu_memory,
-    std::vector<MemorySetting*>* memory_settings,
-    std::vector<std::string>* error_msgs);
-
+void ConstrainToMemoryLimits(int64_t max_cpu_memory,
+                             int64_t max_gpu_memory,
+                             std::vector<MemorySetting*>* memory_settings,
+                             std::vector<std::string>* error_msgs);
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/constrainer_test.cc b/src/cobalt/browser/memory_settings/constrainer_test.cc
index 7a5e3d5..f52bb72 100644
--- a/src/cobalt/browser/memory_settings/constrainer_test.cc
+++ b/src/cobalt/browser/memory_settings/constrainer_test.cc
@@ -29,7 +29,7 @@
 const int64_t kOneMegabyte = 1 * 1024 * 1024;
 const int64_t kTwoMegabytes = 2 * 1024 * 1024;
 const int64_t kFiveMegabytes = 5 * 1024 * 1024;
-const base::optional<int64_t> kNoGpuMemory;
+const int64_t kNoGpuMemory = 0;
 
 ScalingFunction MakeLinearConstrainer() {
   // Linearly scale, but clamp between 0 and 1.
diff --git a/src/cobalt/browser/memory_settings/memory_settings.h b/src/cobalt/browser/memory_settings/memory_settings.h
index 2635c99..52406e8 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.h
+++ b/src/cobalt/browser/memory_settings/memory_settings.h
@@ -90,7 +90,10 @@
   ClassType class_type() const { return class_type_; }
   MemoryType memory_type() const { return memory_type_; }
 
-  bool valid() const { return kNotApplicable != memory_type_; }
+  bool valid() const {
+    return (kNotApplicable != memory_type_) && (kUnset != source_type_);
+  }
+
  protected:
   MemorySetting(ClassType type, const std::string& name);
 
diff --git a/src/cobalt/browser/memory_settings/pretty_print.cc b/src/cobalt/browser/memory_settings/pretty_print.cc
index 41c278c..62b3efc 100644
--- a/src/cobalt/browser/memory_settings/pretty_print.cc
+++ b/src/cobalt/browser/memory_settings/pretty_print.cc
@@ -183,7 +183,7 @@
 }
 
 std::string StringifySourceType(const MemorySetting& setting) {
-  if (!setting.valid()) {
+  if (setting.memory_type() == MemorySetting::kNotApplicable) {
     return "N/A";
   }
 
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 3b43b3d..9e11ce3 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -177,6 +177,14 @@
 // Specifies the maximum GPU usage of the cobalt.
 const char kMaxCobaltGpuUsage[] = "max_cobalt_gpu_usage";
 
+// Reduces the cpu-memory of the system by this amount. This causes AutoMem to
+// reduce the runtime size of the CPU-Memory caches.
+const char kReduceCpuMemoryBy[] = "reduce_cpu_memory_by";
+
+// Reduces the gpu-memory of the system by this amount. This causes AutoMem to
+// reduce the runtime size of the GPU-Memory caches.
+const char kReduceGpuMemoryBy[] = "reduce_gpu_memory_by";
+
 // Specifies the multiplier of video playback rate.  Set to a value greater than
 // 1.0 to play video faster.  Set to a value less than 1.0 to play video slower.
 const char kVideoPlaybackRateMultiplier[] = "video_playback_rate_multiplier";
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 49a5fc7..7eba479 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -62,6 +62,8 @@
 
 extern const char kMaxCobaltCpuUsage[];
 extern const char kMaxCobaltGpuUsage[];
+extern const char kReduceCpuMemoryBy[];
+extern const char kReduceGpuMemoryBy[];
 
 extern const char kVideoPlaybackRateMultiplier[];
 
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index e4dae06..85e3cbf 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-58719
\ No newline at end of file
+61806
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 80b9306..f3941f4 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -164,8 +164,10 @@
     # if this is enabled, we explicitly create an extra offscreen full-size
     # intermediate surface to render into.  Note that some GLES driver
     # implementations may internally allocate an extra full screen surface to
-    # support this feature.
-    'render_dirty_region_only%': 1,
+    # support this feature, and many have been noticed to not properly support
+    # this functionality (but they report that they do), and for these reasons
+    # this value is defaulted to 0.
+    'render_dirty_region_only%': 0,
 
     # Modify this value to adjust the default rasterizer setting for your
     # platform.
@@ -354,6 +356,20 @@
     # SbSystemGetTotalGPUMemory().
     'max_cobalt_gpu_usage%': -1,
 
+    # When specified this value will reduce the cpu memory consumption by
+    # the specified amount. -1 disables the value.
+    # When this value is specified then max_cobalt_cpu_usage will not be
+    # used in memory_constrainer, but will still be used for triggering
+    # a warning if the engine consumes more memory than this value specifies.
+    'reduce_cpu_memory_by%': -1,
+
+    # When specified this value will reduce the gpu memory consumption by
+    # the specified amount. -1 disables the value.
+    # When this value is specified then max_cobalt_gpu_usage will not be
+    # used in memory_constrainer, but will still be used for triggering
+    # a warning if the engine consumes more memory than this value specifies.
+    'reduce_gpu_memory_by%': -1,
+
     # Compiler configuration.
 
     # The following variables are used to specify compiler and linker
diff --git a/src/cobalt/build/gyp_utils.py b/src/cobalt/build/gyp_utils.py
index 4931087..28248ef 100644
--- a/src/cobalt/build/gyp_utils.py
+++ b/src/cobalt/build/gyp_utils.py
@@ -143,7 +143,7 @@
 
   cmd_line = ['goma_ctl.py', 'ensure_start']
   try:
-    subprocess.check_output(cmd_line, shell=True, stderr=subprocess.STDOUT)
+    subprocess.check_output(cmd_line, stderr=subprocess.STDOUT)
     return True
   except subprocess.CalledProcessError as e:
     logging.error('goma failed to start.\nCommand: %s\n%s', ' '.join(e.cmd),
diff --git a/src/cobalt/debug/debug_web_server.cc b/src/cobalt/debug/debug_web_server.cc
index fac8535..76b371f 100644
--- a/src/cobalt/debug/debug_web_server.cc
+++ b/src/cobalt/debug/debug_web_server.cc
@@ -20,6 +20,7 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/logging.h"
+#include "base/optional.h"
 #include "base/path_service.h"
 #include "base/string_util.h"
 #include "build/build_config.h"
@@ -64,7 +65,7 @@
   return "text/plain";
 }
 
-FilePath AppendIndexFile(const FilePath& directory) {
+base::optional<FilePath> AppendIndexFile(const FilePath& directory) {
   DCHECK(file_util::DirectoryExists(directory));
   FilePath result;
   result = directory.AppendASCII("index.html");
@@ -76,7 +77,7 @@
     return result;
   }
   DLOG(ERROR) << "No index file found at: " << directory.value();
-  return directory;
+  return base::nullopt;
 }
 
 std::string GetLocalIpAddress() {
@@ -194,12 +195,20 @@
 
   // If the disk path is a directory, look for an index file.
   if (file_util::DirectoryExists(file_path)) {
-    file_path = AppendIndexFile(file_path);
+    base::optional<FilePath> index_file_path = AppendIndexFile(file_path);
+    if (index_file_path) {
+      file_path = *index_file_path;
+    } else {
+      DLOG(WARNING) << "No index file in directory: " << file_path.value();
+      server_->Send404(connection_id);
+      return;
+    }
   }
 
   // If we can read the local file, send its contents, otherwise send a 404.
   std::string data;
-  if (file_util::ReadFileToString(file_path, &data)) {
+  if (file_util::PathExists(file_path) &&
+      file_util::ReadFileToString(file_path, &data)) {
     DLOG(INFO) << "Sending data from: " << file_path.value();
     std::string mime_type = GetMimeType(file_path);
     server_->Send200(connection_id, data, mime_type);
diff --git a/src/cobalt/doc/performance_tuning.md b/src/cobalt/doc/performance_tuning.md
index b4cfd88..44fc05f 100644
--- a/src/cobalt/doc/performance_tuning.md
+++ b/src/cobalt/doc/performance_tuning.md
@@ -180,13 +180,14 @@
            framerate.*
 
 
-### Ensure that Cobalt is rendering only regions that change
+### Try enabling rendering only to regions that change
 
-Cobalt has logic to detect which part of the frame has been affected by
-animations and can be configured to only render to that region.  However,
-this feature requires support from the driver for GLES platforms.  In
-particular, `eglChooseConfig()` will first be called with
-`EGL_SWAP_BEHAVIOR_PRESERVED_BIT` set in its attribute list.  If this
+If you set the [`base.gypi`](../build/config/base.gypi) variable,
+`render_dirty_region_only` to `1`, then Cobalt will invoke logic to detect which
+part of the frame has been affected by animations and can be configured to only
+render to that region.  However, this feature requires support from the driver
+for GLES platforms.  In particular, `eglChooseConfig()` will first be called
+with `EGL_SWAP_BEHAVIOR_PRESERVED_BIT` set in its attribute list.  If this
 fails, Cobalt will call eglChooseConfig() again without
 `EGL_SWAP_BEHAVIOR_PRESERVED_BIT` set and dirty region rendering will
 be disabled.  By having Cobalt render only small parts of the screen,
@@ -196,7 +197,9 @@
 possible, ensure that your EGL/GLES driver supports
 `EGL_SWAP_BEHAVIOR_PRESERVED_BIT`.  Note that it is possible (but not
 necessary) that GLES drivers will implement this feature by allocating a new
-offscreen buffer, which can significantly affect GPU memory usage.
+offscreen buffer, which can significantly affect GPU memory usage.  If you are
+on a Blitter API platform, enabling this functionality will result in the
+allocation and blit of a fullscreen "intermediate" back buffer target.
 
 **Tags:** *startup, framerate, gpu memory.*
 
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index f42ff0b..85e8006 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -575,6 +575,7 @@
 
     scoped_refptr<HTMLElement> root = html();
     if (root) {
+      DCHECK_EQ(this, root->parent_node());
       // First update the computed style for root element.
       root->UpdateComputedStyle(initial_computed_style_declaration_,
                                 initial_computed_style_data_,
@@ -597,9 +598,11 @@
     return false;
   }
 
-  if (!is_computed_style_dirty_) {
-    return true;
-  }
+  // We explicitly don't short-circuit if the document's
+  // is_computed_style_dirty_ is not set because the specific element we are
+  // updating may have or be under an ancestor element with 'display: none' on
+  // it, in which case the element's computed style will be un-updated despite
+  // the document's is_computed_style_dirty_ being false.
 
   UpdateSelectorTree();
   UpdateKeyframes();
@@ -628,6 +631,7 @@
   // Update computed styles on the ancestors and the element.
   HTMLElement* previous_element = NULL;
   bool ancestors_were_valid = true;
+  scoped_refptr<const cssom::CSSComputedStyleData> root_element_computed_style;
   for (std::vector<HTMLElement*>::reverse_iterator it = ancestors.rbegin();
        it != ancestors.rend(); ++it) {
     HTMLElement* current_element = *it;
@@ -640,7 +644,13 @@
       current_element->UpdateComputedStyle(
           previous_element ? previous_element->css_computed_style_declaration()
                            : initial_computed_style_declaration_,
-          initial_computed_style_data_, style_change_event_time);
+          root_element_computed_style ? root_element_computed_style
+                                      : initial_computed_style_data_,
+          style_change_event_time);
+    }
+    if (!root_element_computed_style) {
+      DCHECK_EQ(this, current_element->parent_node());
+      root_element_computed_style = current_element->computed_style();
     }
     previous_element = current_element;
     ancestors_were_valid = is_valid;
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index 5c049cf..04ef5c5 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -328,7 +328,7 @@
   initial_computed_style_declaration() const {
     return initial_computed_style_declaration_;
   }
-  const scoped_refptr<cssom::CSSComputedStyleData>&
+  const scoped_refptr<const cssom::CSSComputedStyleData>&
   initial_computed_style_data() const {
     return initial_computed_style_data_;
   }
@@ -422,7 +422,7 @@
   // the viewport size.
   scoped_refptr<cssom::CSSComputedStyleDeclaration>
       initial_computed_style_declaration_;
-  scoped_refptr<cssom::CSSComputedStyleData> initial_computed_style_data_;
+  scoped_refptr<const cssom::CSSComputedStyleData> initial_computed_style_data_;
 
   // The max depth of elements that are guaranteed to be rendered.
   int dom_max_element_depth_;
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 954999f..7f7cc7e 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -117,6 +117,7 @@
       volume_(1.0f),
       last_seek_time_(0),
       previous_progress_time_(std::numeric_limits<double>::max()),
+      duration_(std::numeric_limits<double>::quiet_NaN()),
       playing_(false),
       have_fired_loaded_data_(false),
       autoplaying_(true),
@@ -206,12 +207,24 @@
 
 std::string HTMLMediaElement::CanPlayType(const std::string& mime_type,
                                           const std::string& key_system) {
+#if defined(COBALT_MEDIA_SOURCE_2016)
+  DLOG_IF(ERROR, !key_system.empty())
+      << "CanPlayType() only accepts one parameter but (" << key_system
+      << ") is passed as a second parameter.";
+  std::string result =
+      html_element_context()->can_play_type_handler()->CanPlayType(mime_type,
+                                                                   "");
+  MLOG() << "(" << mime_type << ") => " << result;
+  DLOG(INFO) << "HTMLMediaElement::canPlayType(" << mime_type << ") -> "
+             << result;
+#else   // defined(COBALT_MEDIA_SOURCE_2016)
   std::string result =
       html_element_context()->can_play_type_handler()->CanPlayType(mime_type,
                                                                    key_system);
   MLOG() << "(" << mime_type << ", " << key_system << ") => " << result;
   DLOG(INFO) << "HTMLMediaElement::canPlayType(" << mime_type << ", "
              << key_system << ") -> " << result;
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
   return result;
 }
 
@@ -458,14 +471,9 @@
 }
 
 float HTMLMediaElement::duration() const {
-  if (player_ && ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata) {
-    float duration = player_->GetDuration();
-    MLOG() << "player duration: " << duration;
-    return duration;
-  }
-
-  MLOG() << "NaN";
-  return std::numeric_limits<float>::quiet_NaN();
+  MLOG() << duration_;
+  // TODO: Turn duration into double.
+  return static_cast<float>(duration_);
 }
 
 bool HTMLMediaElement::paused() const {
@@ -676,12 +684,12 @@
 void HTMLMediaElement::DurationChanged(double duration, bool request_seek) {
   MLOG() << "DurationChanged(" << duration << ", " << request_seek << ")";
 
-  // TODO: Add cached duration support.
-  /*if (duration_ == duration) {
+  // Abort if duration unchanged.
+  if (duration_ == duration) {
     return;
   }
+  duration_ = duration;
 
-  duration_ = duration;*/
   ScheduleOwnEvent(base::Tokens::durationchange());
 
   if (request_seek) {
@@ -806,6 +814,8 @@
   // The resource selection algorithm
   // 1 - Set the networkState to kNetworkNoSource.
   network_state_ = kNetworkNoSource;
+  // When network_state_ is |kNetworkNoSource|, set duration to NaN.
+  duration_ = std::numeric_limits<double>::quiet_NaN();
 
   // 2 - Asynchronously await a stable state.
   played_time_ranges_ = new TimeRanges;
@@ -1159,6 +1169,7 @@
   if (ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata &&
       old_state < WebMediaPlayer::kReadyStateHaveMetadata) {
     PlayerOutputModeUpdated();
+    duration_ = player_->GetDuration();
     ScheduleOwnEvent(base::Tokens::durationchange());
     ScheduleOwnEvent(base::Tokens::loadedmetadata());
   }
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h
index 9001872..a45eb4e 100644
--- a/src/cobalt/dom/html_media_element.h
+++ b/src/cobalt/dom/html_media_element.h
@@ -291,6 +291,8 @@
   float last_seek_time_;
   double previous_progress_time_;
 
+  double duration_;
+
   bool playing_;
   bool have_fired_loaded_data_;
   bool autoplaying_;
diff --git a/src/cobalt/fetch/embedded_scripts/fetch.js b/src/cobalt/fetch/embedded_scripts/fetch.js
index 884fabb..415739b 100644
--- a/src/cobalt/fetch/embedded_scripts/fetch.js
+++ b/src/cobalt/fetch/embedded_scripts/fetch.js
@@ -1,16 +1,14 @@
-'use strict';(function(g){function p(a){"string"!==typeof a&&(a=String(a));if(/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(a))throw new h("Invalid character in header field name");return a.toLowerCase()}function v(a){"string"!==typeof a&&(a=String(a));var b,d;for(b=0;b<a.length;b++){var c=a.charCodeAt(b);if(9!==c&&10!==c&&13!==c&&32!==c)break}for(d=a.length-1;d>b&&(c=a.charCodeAt(d),9===c||10===c||13===c||32===c);d--);a=a.substring(b,d+1);for(b=0;b<a.length;b++)if(c=a.charCodeAt(b),256<=c||0===c||10===c||13===
-c)throw new h("Invalid character in header field value");return a}function e(a){this.map=new q;if(void 0!==a){if(null===a||"object"!==typeof a)throw new h("Constructing Headers with invalid parameters");a instanceof e?a.forEach(function(a,d){this.append(d,a)},this):m.isArray(a)?a.forEach(function(a){if(2!==a.length)throw new h("Constructing Headers with invalid parameters");this.append(a[0],a[1])},this):Object.getOwnPropertyNames(a).forEach(function(b){this.append(b,a[b])},this)}}function t(a){if(a.bodyUsed)return Promise.reject(new h("Already read"));
-a.bodyUsed=!0}function w(a){return new Promise(function(b,d){a.onload=function(){b(a.result)};a.onerror=function(){d(a.error)}})}function z(a){var b=new FileReader,d=w(b);b.readAsArrayBuffer(a);return d}function A(a){a=new Uint8Array(a);for(var b=new m(a.length),d=0;d<a.length;d++)b[d]=String.fromCharCode(a[d]);return b.join("")}function x(a){if(a.slice)return a.slice(0);var b=new Uint8Array(a.byteLength);b.set(new Uint8Array(a));return b.buffer}function y(){this.bodyUsed=!1;this._initBody=function(a){if(this._bodyInit=
-a)if("string"===typeof a)this._bodyText=a;else if(k.blob&&Blob.prototype.isPrototypeOf(a))this._bodyBlob=a;else if(k.formData&&FormData.prototype.isPrototypeOf(a))this._bodyFormData=a;else if(k.searchParams&&URLSearchParams.prototype.isPrototypeOf(a))this._bodyText=a.toString();else if(k.arrayBuffer&&k.blob&&B(a))this._bodyArrayBuffer=x(a.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer]);else if(k.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(a)||C(a)))this._bodyArrayBuffer=x(a);else throw new u("unsupported BodyInit type");
-else this._bodyText="";this.headers.get("content-type")||("string"===typeof a?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):k.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))};k.blob&&(this.blob=function(){var a=t(this);if(a)return a;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));
-if(this._bodyFormData)throw new u("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){return this._bodyArrayBuffer?t(this)||Promise.resolve(this._bodyArrayBuffer):this.blob().then(z)});this.text=function(){var a=t(this);if(a)return a;if(this._bodyBlob){var a=this._bodyBlob,b=new FileReader,d=w(b);b.readAsText(a);return d}if(this._bodyArrayBuffer)return Promise.resolve(A(this._bodyArrayBuffer));if(this._bodyFormData)throw new u("could not read FormData body as text");
-return Promise.resolve(this._bodyText)};k.formData&&(this.formData=function(){return this.text().then(D)});this.json=function(){return this.text().then(JSON.parse)};return this}function n(a,b){b=b||{};var d=b.body;if(a instanceof n){if(a.bodyUsed)throw new h("Already read");this.url=a.url;this.credentials=a.credentials;b.headers||(this.headers=new e(a.headers));this.method=a.method;this.mode=a.mode;d||null==a._bodyInit||(d=a._bodyInit,a.bodyUsed=!0)}else this.url=String(a);this.credentials=b.credentials||
-this.credentials||"omit";if(b.headers||!this.headers)this.headers=new e(b.headers);a=b.method||this.method||"GET";var c=a.toUpperCase();this.method=-1<E.indexOf(c)?c:a;this.mode=b.mode||this.mode||null;this.referrer=null;if(("GET"===this.method||"HEAD"===this.method)&&d)throw new h("Body not allowed for GET or HEAD requests");this._initBody(d)}function D(a){var b=new FormData;a.trim().split("&").forEach(function(a){if(a){var c=a.split("=");a=c.shift().replace(/\+/g," ");c=c.join("=").replace(/\+/g,
-" ");b.append(decodeURIComponent(a),decodeURIComponent(c))}});return b}function F(a){var b=new e;a.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(a){var c=a.split(":");if(a=c.shift().trim())c=c.join(":").trim(),b.append(a,c)});return b}function l(a,b){b||(b={});this.type="default";this.status="status"in b?b.status:200;this.ok=200<=this.status&&300>this.status;this.statusText="statusText"in b?b.statusText:"OK";this.headers=new e(b.headers);this.url=b.url||"";this._initBody(a)}if(!g.fetch){var m=
-g.Array,u=g.Error,q=g.Map,G=g.RangeError,h=g.TypeError,r;if(r="FileReader"in g&&"Blob"in g)try{new Blob,r=!0}catch(a){r=!1}var k={searchParams:"URLSearchParams"in g,blob:r,formData:"FormData"in g,arrayBuffer:"ArrayBuffer"in g};if(k.arrayBuffer){var H="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";");var B=function(a){return a&&DataView.prototype.isPrototypeOf(a)};
-var C=ArrayBuffer.isView||function(a){return a&&-1<H.indexOf(Object.prototype.toString.call(a))}}e.prototype.append=function(a,b){if(2!==arguments.length)throw h("Invalid parameters to append");a=p(a);b=v(b);this.map.has(a)?this.map.set(a,this.map.get(a)+", "+b):this.map.set(a,b)};e.prototype["delete"]=function(a){if(1!==arguments.length)throw h("Invalid parameters to delete");this.map.delete(p(a))};e.prototype.get=function(a){if(1!==arguments.length)throw h("Invalid parameters to get");a=p(a);var b=
-this.map.get(a);return void 0!==b?b:null};e.prototype.has=function(a){if(1!==arguments.length)throw h("Invalid parameters to has");return this.map.has(p(a))};e.prototype.set=function(a,b){if(2!==arguments.length)throw h("Invalid parameters to set");this.map.set(p(a),v(b))};e.prototype.forEach=function(a,b){var d=this;m.from(this.map.entries()).sort().forEach(function(c){a.call(b,c[1],c[0],d)})};e.prototype.keys=function(){return(new q(m.from(this.map.entries()).sort())).keys()};e.prototype.values=
-function(){return(new q(m.from(this.map.entries()).sort())).values()};e.prototype.entries=function(){return(new q(m.from(this.map.entries()).sort())).entries()};e.prototype[Symbol.iterator]=e.prototype.entries;var E="DELETE GET HEAD OPTIONS POST PUT".split(" ");n.prototype.clone=function(){return new n(this,{body:this._bodyInit})};y.call(n.prototype);y.call(l.prototype);l.prototype.clone=function(){return new l(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new e(this.headers),
-url:this.url})};l.error=function(){var a=new l(null,{status:0,statusText:""});a.type="error";return a};var I=[301,302,303,307,308];l.redirect=function(a,b){if(-1===I.indexOf(b))throw new G("Invalid status code");return new l(null,{status:b,headers:{location:a}})};g.Headers=e;g.Request=n;g.Response=l;g.fetch=function(a,b){return new Promise(function(d,c){var e=new n(a,b),f=new XMLHttpRequest;f.onload=function(){var a={status:f.status,statusText:f.statusText,headers:F(f.getAllResponseHeaders()||"")};
-a.url="responseURL"in f?f.responseURL:a.headers.get("X-Request-URL");d(new l("response"in f?f.response:f.responseText,a))};f.onerror=function(){c(new h("Network request failed"))};f.ontimeout=function(){c(new h("Network request failed"))};f.open(e.method,e.url,!0);"include"===e.credentials&&(f.withCredentials=!0);"responseType"in f&&k.blob&&(f.responseType="blob");e.headers.forEach(function(a,b){f.setRequestHeader(b,a)});f.send("undefined"===typeof e._bodyInit?null:e._bodyInit)})};g.fetch.polyfill=
-!0}})(this);
\ No newline at end of file
+'use strict';(function(f){function n(a){"string"!==typeof a&&(a=String(a));if(/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(a))throw new h("Invalid character in header field name");return a.toLowerCase()}function w(a){"string"!==typeof a&&(a=String(a));var b;var c=0;for(b=a.length;c<b;c++){var d=a.charCodeAt(c);if(9!==d&&10!==d&&13!==d&&32!==d)break}for(b=a.length-1;b>c&&(d=a.charCodeAt(b),9===d||10===d||13===d||32===d);b--);a=a.substring(c,b+1);c=0;for(b=a.length;c<b;c++)if(d=a.charCodeAt(c),256<=d||0===d||
+10===d||13===d)throw new h("Invalid character in header field value");return a}function e(a){this.map=new q;if(void 0!==a){if(null===a||"object"!==typeof a)throw new h("Constructing Headers with invalid parameters");a instanceof e?a.forEach(function(a,c){this.append(c,a)},this):m.isArray(a)?a.forEach(function(a){if(2!==a.length)throw new h("Constructing Headers with invalid parameters");this.append(a[0],a[1])},this):Object.getOwnPropertyNames(a).forEach(function(b){this.append(b,a[b])},this)}}function r(a){if(a.bodyUsed)return t(new h("Body already read"));
+if(null===a.body)return A(new k(0));if(B(a.body))return t(new h("ReadableStream already locked"));var b=a.body.getReader(),c=[],d=0;return b.read().then(function C(a){if(a.done){if(0===c.length)a=new k(0);else if(1===c.length)a=new k(c[0]);else{a=new k(d);for(var f=0,e=c.length,g=0;f<e;f++)a.set(c[f],g),g+=c[f].length}return a}return a.value instanceof k?(d+=a.value.length,c.push(a.value),b.read().then(C)):t(new h("Invalid stream read value type"))})}function D(a){a=unescape(encodeURIComponent(a));
+for(var b=new k(a.length),c=0,d=a.length;c<d;c++)b[c]=a.charCodeAt(c);return b}function x(){this._initBody=function(a){this._bodyUsed=!1;this.body=null===a||void 0===a?null:a instanceof u?a:new u({start:function(b){if(a)if("string"===typeof a)b.enqueue(D(a));else if(y.prototype.isPrototypeOf(a))b.enqueue(new k(a));else if(E(a))b.enqueue(new k(a.buffer));else throw new h("Unsupported BodyInit type");b.close()}});this.headers.get("content-type")||"string"===typeof a&&this.headers.set("content-type",
+"text/plain;charset=UTF-8")};Object.defineProperty(this,"bodyUsed",{get:function(){return this._bodyUsed?!0:this.body?!!F(this.body):!1}});this.arrayBuffer=function(){return r(this).then(function(a){return a.buffer})};this.text=function(){return r(this).then(function(a){return 0===a.length?"":decodeURIComponent(escape(String.fromCharCode.apply(null,a)))})};this.json=function(){return this.text().then(JSON.parse)};return this}function p(a,b){b=b||{};var c=b.body;if(a instanceof p){if(a.bodyUsed)throw new h("Request body already read");
+this.url=a.url;this.credentials=a.credentials;b.headers||(this.headers=new e(a.headers));this.method=a.method;this.mode=a.mode;c||null===a.body||(c=a.body,a._bodyUsed=!0)}else this.url=String(a);this.credentials=b.credentials||this.credentials||"omit";if(b.headers||!this.headers)this.headers=new e(b.headers);a=b.method||this.method||"GET";var d=a.toUpperCase();this.method=-1<G.indexOf(d)?d:a;this.mode=b.mode||this.mode||null;this.referrer=null;if(("GET"===this.method||"HEAD"===this.method)&&c)throw new h("Body not allowed for GET or HEAD requests");
+this._initBody(c)}function H(a){var b=new e;a.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(a){var c=a.split(":");if(a=c.shift().trim())c=c.join(":").trim(),b.append(a,c)});return b}function l(a,b){b||(b={});this.type="default";this.status="status"in b?b.status:200;this.ok=200<=this.status&&300>this.status;this.statusText="statusText"in b?b.statusText:"OK";this.headers=new e(b.headers);this.url=b.url||"";this._initBody(a)}if(!f.fetch){var m=f.Array,y=f.ArrayBuffer,I=f.Symbol.iterator,
+q=f.Map,J=f.RangeError,h=f.TypeError,k=f.Uint8Array,v=f.Promise,t=v.reject,A=v.resolve,u=f.ReadableStream,z=f.ReadableStreamTee,F=f.IsReadableStreamDisturbed,B=f.IsReadableStreamLocked,K="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";"),E=y.isView||function(a){return a&&-1<K.indexOf(Object.prototype.toString.call(a))};e.prototype.append=function(a,
+b){if(2!==arguments.length)throw h("Invalid parameters to append");a=n(a);b=w(b);this.map.has(a)?this.map.set(a,this.map.get(a)+", "+b):this.map.set(a,b)};e.prototype["delete"]=function(a){if(1!==arguments.length)throw h("Invalid parameters to delete");this.map.delete(n(a))};e.prototype.get=function(a){if(1!==arguments.length)throw h("Invalid parameters to get");a=n(a);var b=this.map.get(a);return void 0!==b?b:null};e.prototype.has=function(a){if(1!==arguments.length)throw h("Invalid parameters to has");
+return this.map.has(n(a))};e.prototype.set=function(a,b){if(2!==arguments.length)throw h("Invalid parameters to set");this.map.set(n(a),w(b))};e.prototype.forEach=function(a,b){var c=this;m.from(this.map.entries()).sort().forEach(function(d){a.call(b,d[1],d[0],c)})};e.prototype.keys=function(){return(new q(m.from(this.map.entries()).sort())).keys()};e.prototype.values=function(){return(new q(m.from(this.map.entries()).sort())).values()};e.prototype.entries=function(){return(new q(m.from(this.map.entries()).sort())).entries()};
+e.prototype[I]=e.prototype.entries;var G="DELETE GET HEAD OPTIONS POST PUT".split(" ");p.prototype.clone=function(){var a=null;null!==this.body&&(a=z(this.body,!0),this.body=a[0],a=a[1]);return new p(this,{body:a})};x.call(p.prototype);x.call(l.prototype);l.prototype.clone=function(){var a=null;null!==this.body&&(a=z(this.body,!0),this.body=a[0],a=a[1]);return new l(a,{status:this.status,statusText:this.statusText,headers:new e(this.headers),url:this.url})};l.error=function(){var a=new l(null,{status:0,
+statusText:""});a.type="error";return a};var L=[301,302,303,307,308];l.redirect=function(a,b){if(-1===L.indexOf(b))throw new J("Invalid status code");return new l(null,{status:b,headers:{location:a}})};f.Headers=e;f.Request=p;f.Response=l;f.fetch=function(a,b){return new v(function(c,d){var f=!1,e=new p(a,b),g=new XMLHttpRequest,k=null,n=new u({start:function(a){k=a},cancel:function(a){f=!0;g.abort()}});g.onload=function(){k.close()};g.onreadystatechange=function(){if(g.readyState===g.HEADERS_RECEIVED){var a=
+{status:g.status,statusText:g.statusText,headers:H(g.getAllResponseHeaders()||"")};a.url="responseURL"in g?g.responseURL:a.headers.get("X-Request-URL");c(new l(n,a))}};g.onerror=function(){k.error(new h("Network request failed"));d(new h("Network request failed"))};g.ontimeout=function(){k.error(new h("Network request failed"));d(new h("Network request failed"))};g.open(e.method,e.url,!0);"include"===e.credentials&&(g.withCredentials=!0);e.headers.forEach(function(a,b){g.setRequestHeader(b,a)});var m=
+function(a){f||k.enqueue(a)};null===e.body?g.fetch(m,null):r(e).then(function(a){g.fetch(m,a)})})};f.fetch.polyfill=!0}})(this);
\ No newline at end of file
diff --git a/src/cobalt/fetch/fetch.js b/src/cobalt/fetch/fetch.js
index b01d35f..9201ff8 100644
--- a/src/cobalt/fetch/fetch.js
+++ b/src/cobalt/fetch/fetch.js
@@ -35,48 +35,41 @@
     return
   }
 
-  var Array = self.Array;
-  var Error = self.Error;
-  var Map = self.Map;
-  var RangeError = self.RangeError;
-  var TypeError = self.TypeError;
+  var Array = self.Array
+  var ArrayBuffer = self.ArrayBuffer
+  var Error = self.Error
+  var Symbol_iterator = self.Symbol.iterator
+  var Map = self.Map
+  var RangeError = self.RangeError
+  var TypeError = self.TypeError
+  var Uint8Array = self.Uint8Array
+
+  var Promise = self.Promise
+  var Promise_reject = Promise.reject
+  var Promise_resolve = Promise.resolve
+
+  var ReadableStream = self.ReadableStream
+  var ReadableStreamTee = self.ReadableStreamTee
+  var IsReadableStreamDisturbed = self.IsReadableStreamDisturbed
+  var IsReadableStreamLocked = self.IsReadableStreamLocked
 
   var err_InvalidHeadersInit = 'Constructing Headers with invalid parameters'
+  var err_NetworkRequestFailed = 'Network request failed'
 
-  var support = {
-    searchParams: 'URLSearchParams' in self,
-    blob: 'FileReader' in self && 'Blob' in self && (function() {
-      try {
-        new Blob()
-        return true
-      } catch(e) {
-        return false
-      }
-    })(),
-    formData: 'FormData' in self,
-    arrayBuffer: 'ArrayBuffer' in self
-  }
+  var viewClasses = [
+    '[object Int8Array]',
+    '[object Uint8Array]',
+    '[object Uint8ClampedArray]',
+    '[object Int16Array]',
+    '[object Uint16Array]',
+    '[object Int32Array]',
+    '[object Uint32Array]',
+    '[object Float32Array]',
+    '[object Float64Array]'
+  ]
 
-  if (support.arrayBuffer) {
-    var viewClasses = [
-      '[object Int8Array]',
-      '[object Uint8Array]',
-      '[object Uint8ClampedArray]',
-      '[object Int16Array]',
-      '[object Uint16Array]',
-      '[object Int32Array]',
-      '[object Uint32Array]',
-      '[object Float32Array]',
-      '[object Float64Array]'
-    ]
-
-    var isDataView = function(obj) {
-      return obj && DataView.prototype.isPrototypeOf(obj)
-    }
-
-    var isArrayBufferView = ArrayBuffer.isView || function(obj) {
-      return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
-    }
+  var isArrayBufferView = ArrayBuffer.isView || function(obj) {
+    return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
   }
 
   function normalizeName(name) {
@@ -99,10 +92,10 @@
     // permissive approach that passes the tests while following the spirit
     // of the spec. Essentially, leading & trailing HTTP whitespace bytes
     // are trimmed first before checking validity.
-    var c, first, last, i
+    var c, first, last, i, len
 
     //value = value.replace(/^[ \t\n\r]+|[ \t\n\r]+$/g, '')
-    for (first = 0; first < value.length; first++) {
+    for (first = 0, len = value.length; first < len; first++) {
       c = value.charCodeAt(first)
       if (c !== 9 && c !== 10 && c !== 13 && c !== 32) {
         break
@@ -118,7 +111,7 @@
 
     // Follow the chromium implementation of IsValidHTTPHeaderValue(). This
     // should be updated once the web platform test abides by the fetch spec.
-    for (i = 0; i < value.length; i++) {
+    for (i = 0, len = value.length; i < len; i++) {
       c = value.charCodeAt(i)
       if (c >= 256 || c === 0 || c === 10 || c === 13) {
         throw new TypeError('Invalid character in header field value')
@@ -127,6 +120,7 @@
     return value
   }
 
+  // https://fetch.spec.whatwg.org/#headers-class
   function Headers(headers) {
     this.map = new Map();
 
@@ -220,144 +214,130 @@
     return sorted_map.entries()
   }
 
-  Headers.prototype[Symbol.iterator] = Headers.prototype.entries
+  Headers.prototype[Symbol_iterator] = Headers.prototype.entries
 
-  function consumed(body) {
+  function consumeBodyAsUint8Array(body) {
     if (body.bodyUsed) {
-      return Promise.reject(new TypeError('Already read'))
+      return Promise_reject(new TypeError('Body already read'))
     }
-    body.bodyUsed = true
-  }
 
-  function fileReaderReady(reader) {
-    return new Promise(function(resolve, reject) {
-      reader.onload = function() {
-        resolve(reader.result)
-      }
-      reader.onerror = function() {
-        reject(reader.error)
+    if (body.body === null) {
+      return Promise_resolve(new Uint8Array(0))
+    }
+
+    if (IsReadableStreamLocked(body.body)) {
+      return Promise_reject(new TypeError('ReadableStream already locked'))
+    }
+
+    var reader = body.body.getReader()
+    var results = []
+    var resultsLength = 0
+    return reader.read().then(function addResult(result) {
+      if (result.done) {
+        var data
+        if (results.length === 0) {
+          data = new Uint8Array(0)
+        } else if (results.length === 1) {
+          data = new Uint8Array(results[0])
+        } else {
+          data = new Uint8Array(resultsLength)
+          for (var i = 0, len = results.length, offset = 0; i < len; i++) {
+            data.set(results[i], offset)
+            offset += results[i].length
+          }
+        }
+        return data
+      } else if (result.value instanceof Uint8Array) {
+        resultsLength += result.value.length
+        results.push(result.value)
+        return reader.read().then(addResult)
+      } else {
+        return Promise_reject(new TypeError('Invalid stream read value type'))
       }
     })
   }
 
-  function readBlobAsArrayBuffer(blob) {
-    var reader = new FileReader()
-    var promise = fileReaderReady(reader)
-    reader.readAsArrayBuffer(blob)
-    return promise
-  }
-
-  function readBlobAsText(blob) {
-    var reader = new FileReader()
-    var promise = fileReaderReady(reader)
-    reader.readAsText(blob)
-    return promise
-  }
-
-  function readArrayBufferAsText(buf) {
-    var view = new Uint8Array(buf)
-    var chars = new Array(view.length)
-
-    for (var i = 0; i < view.length; i++) {
-      chars[i] = String.fromCharCode(view[i])
+  function encodeStringToUint8Array(str) {
+    // Encode string to UTF-8 then store it in an Uint8Array.
+    var utf8 = unescape(encodeURIComponent(str))
+    var uint8 = new Uint8Array(utf8.length)
+    for (var i = 0, len = utf8.length; i < len; i++) {
+      uint8[i] = utf8.charCodeAt(i)
     }
-    return chars.join('')
+    return uint8
   }
 
-  function bufferClone(buf) {
-    if (buf.slice) {
-      return buf.slice(0)
+  function decodeStringFromUint8Array(uint8) {
+    // Decode string from UTF-8 that is stored in the Uint8Array.
+    return decodeURIComponent(escape(String.fromCharCode.apply(null, uint8)))
+  }
+
+  // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
+  function extractBody(controller, data, errorString) {
+    if (!data) {
+    } else if (typeof data === 'string') {
+      controller.enqueue(encodeStringToUint8Array(data))
+    } else if (ArrayBuffer.prototype.isPrototypeOf(data)) {
+      controller.enqueue(new Uint8Array(data))
+    } else if (isArrayBufferView(data)) {
+      controller.enqueue(new Uint8Array(data.buffer))
     } else {
-      var view = new Uint8Array(buf.byteLength)
-      view.set(new Uint8Array(buf))
-      return view.buffer
+      throw new TypeError(errorString)
     }
   }
 
+  // https://fetch.spec.whatwg.org/#body-mixin
+  // However, our engine does not fully support URLSearchParams, FormData, nor
+  //   Blob types. So only support text(), arrayBuffer(), and json().
   function Body() {
-    this.bodyUsed = false
-
     this._initBody = function(body) {
-      this._bodyInit = body
-      if (!body) {
-        this._bodyText = ''
-      } else if (typeof body === 'string') {
-        this._bodyText = body
-      } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
-        this._bodyBlob = body
-      } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
-        this._bodyFormData = body
-      } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
-        this._bodyText = body.toString()
-      } else if (support.arrayBuffer && support.blob && isDataView(body)) {
-        this._bodyArrayBuffer = bufferClone(body.buffer)
-        // IE 10-11 can't handle a DataView body.
-        this._bodyInit = new Blob([this._bodyArrayBuffer])
-      } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
-        this._bodyArrayBuffer = bufferClone(body)
+      this._bodyUsed = false
+      if (body === null || body === undefined) {
+        this.body = null
+      } else if (body instanceof ReadableStream) {
+        this.body = body
       } else {
-        throw new Error('unsupported BodyInit type')
+        this.body = new ReadableStream({
+          start(controller) {
+            extractBody(controller, body, 'Unsupported BodyInit type')
+            controller.close()
+          }
+        })
       }
 
       if (!this.headers.get('content-type')) {
         if (typeof body === 'string') {
           this.headers.set('content-type', 'text/plain;charset=UTF-8')
-        } else if (this._bodyBlob && this._bodyBlob.type) {
-          this.headers.set('content-type', this._bodyBlob.type)
-        } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
-          this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
         }
       }
     }
 
-    if (support.blob) {
-      this.blob = function() {
-        var rejected = consumed(this)
-        if (rejected) {
-          return rejected
-        }
-
-        if (this._bodyBlob) {
-          return Promise.resolve(this._bodyBlob)
-        } else if (this._bodyArrayBuffer) {
-          return Promise.resolve(new Blob([this._bodyArrayBuffer]))
-        } else if (this._bodyFormData) {
-          throw new Error('could not read FormData body as blob')
+    Object.defineProperty(this, 'bodyUsed', {
+      get: function() {
+        if (this._bodyUsed) {
+          return true
+        } else if (this.body) {
+          return !!IsReadableStreamDisturbed(this.body)
         } else {
-          return Promise.resolve(new Blob([this._bodyText]))
+          return false
         }
       }
+    })
 
-      this.arrayBuffer = function() {
-        if (this._bodyArrayBuffer) {
-          return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
-        } else {
-          return this.blob().then(readBlobAsArrayBuffer)
-        }
-      }
+    this.arrayBuffer = function() {
+      return consumeBodyAsUint8Array(this).then(function(data) {
+        return data.buffer
+      })
     }
 
     this.text = function() {
-      var rejected = consumed(this)
-      if (rejected) {
-        return rejected
-      }
-
-      if (this._bodyBlob) {
-        return readBlobAsText(this._bodyBlob)
-      } else if (this._bodyArrayBuffer) {
-        return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
-      } else if (this._bodyFormData) {
-        throw new Error('could not read FormData body as text')
-      } else {
-        return Promise.resolve(this._bodyText)
-      }
-    }
-
-    if (support.formData) {
-      this.formData = function() {
-        return this.text().then(decode)
-      }
+      return consumeBodyAsUint8Array(this).then(function(data) {
+        if (data.length === 0) {
+          return ''
+        } else {
+          return decodeStringFromUint8Array(data)
+        }
+      })
     }
 
     this.json = function() {
@@ -375,35 +355,37 @@
     return (methods.indexOf(upcased) > -1) ? upcased : method
   }
 
-  function Request(input, options) {
-    options = options || {}
-    var body = options.body
+  // https://fetch.spec.whatwg.org/#request-class
+  function Request(input, init) {
+    init = init || {}
+    var body = init.body
 
     if (input instanceof Request) {
       if (input.bodyUsed) {
-        throw new TypeError('Already read')
+        throw new TypeError('Request body already read')
       }
       this.url = input.url
       this.credentials = input.credentials
-      if (!options.headers) {
+      if (!init.headers) {
         this.headers = new Headers(input.headers)
       }
       this.method = input.method
       this.mode = input.mode
-      if (!body && input._bodyInit != null) {
-        body = input._bodyInit
-        input.bodyUsed = true
+      if (!body && input.body !== null) {
+        // Take ownership of the stream and mark |input| as disturbed.
+        body = input.body
+        input._bodyUsed = true
       }
     } else {
       this.url = String(input)
     }
 
-    this.credentials = options.credentials || this.credentials || 'omit'
-    if (options.headers || !this.headers) {
-      this.headers = new Headers(options.headers)
+    this.credentials = init.credentials || this.credentials || 'omit'
+    if (init.headers || !this.headers) {
+      this.headers = new Headers(init.headers)
     }
-    this.method = normalizeMethod(options.method || this.method || 'GET')
-    this.mode = options.mode || this.mode || null
+    this.method = normalizeMethod(init.method || this.method || 'GET')
+    this.mode = init.mode || this.mode || null
     this.referrer = null
 
     if ((this.method === 'GET' || this.method === 'HEAD') && body) {
@@ -413,20 +395,13 @@
   }
 
   Request.prototype.clone = function() {
-    return new Request(this, { body: this._bodyInit })
-  }
-
-  function decode(body) {
-    var form = new FormData()
-    body.trim().split('&').forEach(function(bytes) {
-      if (bytes) {
-        var split = bytes.split('=')
-        var name = split.shift().replace(/\+/g, ' ')
-        var value = split.join('=').replace(/\+/g, ' ')
-        form.append(decodeURIComponent(name), decodeURIComponent(value))
-      }
-    })
-    return form
+    var cloneBody = null
+    if (this.body !== null) {
+      var streams = ReadableStreamTee(this.body, true /* cloneForBranch2 */)
+      this.body = streams[0]
+      cloneBody = streams[1]
+    }
+    return new Request(this, { body: cloneBody })
   }
 
   function parseHeaders(rawHeaders) {
@@ -447,24 +422,31 @@
 
   Body.call(Request.prototype)
 
-  function Response(bodyInit, options) {
-    if (!options) {
-      options = {}
+  // https://fetch.spec.whatwg.org/#response-class
+  function Response(body, init) {
+    if (!init) {
+      init = {}
     }
 
     this.type = 'default'
-    this.status = 'status' in options ? options.status : 200
+    this.status = 'status' in init ? init.status : 200
     this.ok = this.status >= 200 && this.status < 300
-    this.statusText = 'statusText' in options ? options.statusText : 'OK'
-    this.headers = new Headers(options.headers)
-    this.url = options.url || ''
-    this._initBody(bodyInit)
+    this.statusText = 'statusText' in init ? init.statusText : 'OK'
+    this.headers = new Headers(init.headers)
+    this.url = init.url || ''
+    this._initBody(body)
   }
 
   Body.call(Response.prototype)
 
   Response.prototype.clone = function() {
-    return new Response(this._bodyInit, {
+    var cloneBody = null
+    if (this.body !== null) {
+      var streams = ReadableStreamTee(this.body, true /* cloneForBranch2 */)
+      this.body = streams[0]
+      cloneBody = streams[1]
+    }
+    return new Response(cloneBody, {
       status: this.status,
       statusText: this.statusText,
       headers: new Headers(this.headers),
@@ -494,26 +476,45 @@
 
   self.fetch = function(input, init) {
     return new Promise(function(resolve, reject) {
+      var cancelled = false
       var request = new Request(input, init)
       var xhr = new XMLHttpRequest()
 
-      xhr.onload = function() {
-        var options = {
-          status: xhr.status,
-          statusText: xhr.statusText,
-          headers: parseHeaders(xhr.getAllResponseHeaders() || '')
+      var responseStreamController = null
+      var responseStream = new ReadableStream({
+        start(controller) {
+          responseStreamController = controller
+        },
+        cancel(controller) {
+          cancelled = true
+          xhr.abort()
         }
-        options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
-        var body = 'response' in xhr ? xhr.response : xhr.responseText
-        resolve(new Response(body, options))
+      })
+
+      xhr.onload = function() {
+        responseStreamController.close()
+      }
+
+      xhr.onreadystatechange = function() {
+        if (xhr.readyState === xhr.HEADERS_RECEIVED) {
+          var init = {
+            status: xhr.status,
+            statusText: xhr.statusText,
+            headers: parseHeaders(xhr.getAllResponseHeaders() || '')
+          }
+          init.url = 'responseURL' in xhr ? xhr.responseURL : init.headers.get('X-Request-URL')
+          resolve(new Response(responseStream, init))
+        }
       }
 
       xhr.onerror = function() {
-        reject(new TypeError('Network request failed'))
+        responseStreamController.error(new TypeError(err_NetworkRequestFailed))
+        reject(new TypeError(err_NetworkRequestFailed))
       }
 
       xhr.ontimeout = function() {
-        reject(new TypeError('Network request failed'))
+        responseStreamController.error(new TypeError(err_NetworkRequestFailed))
+        reject(new TypeError(err_NetworkRequestFailed))
       }
 
       xhr.open(request.method, request.url, true)
@@ -522,15 +523,24 @@
         xhr.withCredentials = true
       }
 
-      if ('responseType' in xhr && support.blob) {
-        xhr.responseType = 'blob'
-      }
-
       request.headers.forEach(function(value, name) {
         xhr.setRequestHeader(name, value)
       })
 
-      xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
+      var fetchUpdate = function(data) {
+        if (!cancelled) {
+          // Data is already an Uint8Array.
+          responseStreamController.enqueue(data)
+        }
+      }
+
+      if (request.body === null) {
+        xhr.fetch(fetchUpdate, null)
+      } else {
+        consumeBodyAsUint8Array(request).then(function(data) {
+          xhr.fetch(fetchUpdate, data)
+        })
+      }
     })
   }
   self.fetch.polyfill = true
diff --git a/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt b/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt
new file mode 100644
index 0000000..f32ceb8
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt
@@ -0,0 +1,112 @@
+# Fetch API tests
+api/basic/block-mime-as-script.html,DISABLE
+api/basic/conditional-get.html,DISABLE
+api/basic/error-after-response.html,DISABLE
+api/basic/integrity.html,DISABLE
+api/basic/integrity-sharedworker.html,DISABLE
+api/basic/integrity-worker.html,DISABLE
+api/basic/mode-no-cors.html,DISABLE
+api/basic/mode-no-cors-worker.html,DISABLE
+api/basic/request-referrer-redirected-worker.html,DISABLE
+# Failures due to XHR not implementing response url list.
+api/basic/response-url.html,DISABLE
+api/basic/response-url-worker.html,DISABLE
+# Failures due to engine not supporting Blob type.
+api/basic/scheme-blob.html,DISABLE
+api/basic/scheme-blob-worker.html,DISABLE
+api/basic/scheme-others.html,PASS
+api/basic/scheme-others-worker.html,DISABLE
+api/basic/text-utf8.html,DISABLE
+api/cors/cors-expose-star.html,DISABLE
+api/cors/cors-expose-star-worker.html,DISABLE
+api/cors/cors-filtering.html,DISABLE
+api/cors/cors-filtering-worker.html,DISABLE
+api/cors/cors-multiple-origins.html,DISABLE
+api/cors/cors-multiple-origins-worker.html,DISABLE
+# Failures due to built-in Map iterator not conforming.
+api/headers/headers-basic.html,DISABLE
+api/headers/headers-casing.html,PASS
+api/headers/headers-combine.html,PASS
+api/headers/headers-errors.html,PASS
+# Failures due to being a polyfill.
+api/headers/headers-idl.html,DISABLE
+api/headers/headers-normalize.html,PASS
+# Failures due to Reflect not working with the polyfill.
+api/headers/headers-record.html,DISABLE
+api/headers/headers-structure.html,PASS
+# Invalid: this tests XHR
+api/headers/header-values.html,DISABLE
+# Invalid: this tests XHR
+api/headers/header-values-normalize.html,DISABLE
+api/policies/csp-blocked.html,DISABLE
+api/policies/csp-blocked-worker.html,DISABLE
+api/policies/referrer-no-referrer.html,DISABLE
+api/policies/referrer-no-referrer-service-worker.https.html,DISABLE
+api/policies/referrer-no-referrer-worker.html,DISABLE
+api/policies/referrer-origin.html,DISABLE
+api/policies/referrer-origin-service-worker.https.html,DISABLE
+api/policies/referrer-origin-when-cross-origin.html,DISABLE
+api/policies/referrer-origin-when-cross-origin-service-worker.https.html,DISABLE
+api/policies/referrer-origin-when-cross-origin-worker.html,DISABLE
+api/policies/referrer-origin-worker.html,DISABLE
+api/policies/referrer-unsafe-url.html,DISABLE
+api/policies/referrer-unsafe-url-service-worker.https.html,DISABLE
+api/policies/referrer-unsafe-url-worker.html,DISABLE
+api/redirect/redirect-count.html,DISABLE
+api/redirect/redirect-count-worker.html,DISABLE
+api/redirect/redirect-location.html,DISABLE
+api/redirect/redirect-location-worker.html,DISABLE
+api/redirect/redirect-method.html,DISABLE
+api/redirect/redirect-method-worker.html,DISABLE
+api/redirect/redirect-mode.html,DISABLE
+api/redirect/redirect-mode-worker.html,DISABLE
+api/redirect/redirect-origin.html,DISABLE
+api/redirect/redirect-origin-worker.html,DISABLE
+api/redirect/redirect-referrer.html,DISABLE
+api/redirect/redirect-referrer-worker.html,DISABLE
+api/redirect/redirect-schemes.html,DISABLE
+api/redirect/redirect-to-dataurl.html,DISABLE
+api/redirect/redirect-to-dataurl-worker.html,DISABLE
+api/request/multi-globals/url-parsing.html,DISABLE
+api/request/request-bad-port.html,PASS
+api/request/request-cache-default.html,DISABLE
+api/request/request-cache-default-conditional.html,DISABLE
+api/request/request-cache-force-cache.html,DISABLE
+api/request/request-cache-no-cache.html,PASS
+api/request/request-cache-no-store.html,PASS
+api/request/request-cache-only-if-cached.html,DISABLE
+api/request/request-cache-reload.html,DISABLE
+api/request/request-clone.sub.html,DISABLE
+api/request/request-consume.html,DISABLE
+api/request/request-consume-empty.html,DISABLE
+api/request/request-disturbed.html,DISABLE
+api/request/request-error.html,DISABLE
+api/request/request-headers.html,DISABLE
+api/request/request-idl.html,DISABLE
+api/request/request-init-001.sub.html,DISABLE
+api/request/request-init-002.html,DISABLE
+api/request/request-init-003.sub.html,DISABLE
+api/request/request-keepalive-quota.html,DISABLE
+api/request/request-structure.html,DISABLE
+api/response/multi-globals/url-parsing.html,DISABLE
+# "*.cobalt.html" tests only check Body text(), arraybuffer(), json()
+api/response/response-cancel-stream.html,DISABLE
+api/response/response-clone.html,PASS
+api/response/response-consume.cobalt.html,PASS
+api/response/response-consume.html,DISABLE
+api/response/response-consume-empty.cobalt.html,PASS
+api/response/response-consume-empty.html,DISABLE
+api/response/response-consume-stream.cobalt.html,PASS
+api/response/response-consume-stream.html,DISABLE
+api/response/response-error.html,DISABLE
+api/response/response-idl.html,DISABLE
+api/response/response-init-001.html,PASS
+api/response/response-init-002.html,PASS
+api/response/response-static-error.html,PASS
+api/response/response-static-redirect.html,DISABLE
+api/response/response-stream-disturbed-1.html,PASS
+api/response/response-stream-disturbed-2.html,PASS
+api/response/response-stream-disturbed-3.html,PASS
+api/response/response-stream-disturbed-4.html,PASS
+api/response/response-stream-disturbed-5.html,PASS
+api/response/response-trailer.html,DISABLE
diff --git a/src/cobalt/layout_tests/testdata/web-platform-tests/streams/web_platform_tests.txt b/src/cobalt/layout_tests/testdata/web-platform-tests/streams/web_platform_tests.txt
new file mode 100644
index 0000000..22e8ab1
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/web-platform-tests/streams/web_platform_tests.txt
@@ -0,0 +1,61 @@
+# Streams API tests.
+#
+# Worker-related tests are not relevant. Disable them.
+byte-length-queuing-strategy.dedicatedworker.html,DISABLE
+byte-length-queuing-strategy.html,PASS
+byte-length-queuing-strategy.serviceworker.https.html,DISABLE
+byte-length-queuing-strategy.sharedworker.html,DISABLE
+count-queuing-strategy.dedicatedworker.html,DISABLE
+count-queuing-strategy.html,PASS
+count-queuing-strategy.serviceworker.https.html,DISABLE
+count-queuing-strategy.sharedworker.html,DISABLE
+readable-streams/bad-strategies.dedicatedworker.html,DISABLE
+readable-streams/bad-strategies.html,PASS
+readable-streams/bad-strategies.serviceworker.https.html,DISABLE
+readable-streams/bad-strategies.sharedworker.html,DISABLE
+readable-streams/bad-underlying-sources.dedicatedworker.html,DISABLE
+readable-streams/bad-underlying-sources.html,PASS
+readable-streams/bad-underlying-sources.serviceworker.https.html,DISABLE
+readable-streams/bad-underlying-sources.sharedworker.html,DISABLE
+readable-streams/brand-checks.dedicatedworker.html,DISABLE
+readable-streams/brand-checks.html,PASS
+readable-streams/brand-checks.serviceworker.https.html,DISABLE
+readable-streams/brand-checks.sharedworker.html,DISABLE
+readable-streams/cancel.dedicatedworker.html,DISABLE
+readable-streams/cancel.html,PASS
+readable-streams/cancel.serviceworker.https.html,DISABLE
+readable-streams/cancel.sharedworker.html,DISABLE
+readable-streams/count-queuing-strategy-integration.dedicatedworker.html,DISABLE
+readable-streams/count-queuing-strategy-integration.html,PASS
+readable-streams/count-queuing-strategy-integration.serviceworker.https.html,DISABLE
+readable-streams/count-queuing-strategy-integration.sharedworker.html,DISABLE
+readable-streams/default-reader.dedicatedworker.html,DISABLE
+readable-streams/default-reader.html,PASS
+readable-streams/default-reader.serviceworker.https.html,DISABLE
+readable-streams/default-reader.sharedworker.html,DISABLE
+# Some floating point pass, but the more esoteric ones fail.
+readable-streams/floating-point-total-queue-size.dedicatedworker.html,DISABLE
+readable-streams/floating-point-total-queue-size.html,DISABLE
+readable-streams/floating-point-total-queue-size.serviceworker.https.html,DISABLE
+readable-streams/floating-point-total-queue-size.sharedworker.html,DISABLE
+readable-streams/garbage-collection.dedicatedworker.html,DISABLE
+readable-streams/garbage-collection.html,PASS
+readable-streams/garbage-collection.serviceworker.https.html,DISABLE
+readable-streams/garbage-collection.sharedworker.html,DISABLE
+readable-streams/general.dedicatedworker.html,DISABLE
+readable-streams/general.html,PASS
+readable-streams/general.serviceworker.https.html,DISABLE
+readable-streams/general.sharedworker.html,DISABLE
+# pipeThrough is not supported / implemented.
+readable-streams/pipe-through.dedicatedworker.html,DISABLE
+readable-streams/pipe-through.html,DISABLE
+readable-streams/pipe-through.serviceworker.https.html,DISABLE
+readable-streams/pipe-through.sharedworker.html,DISABLE
+readable-streams/tee.dedicatedworker.html,DISABLE
+readable-streams/tee.html,PASS
+readable-streams/tee.serviceworker.https.html,DISABLE
+readable-streams/tee.sharedworker.html,DISABLE
+readable-streams/templated.dedicatedworker.html,DISABLE
+readable-streams/templated.html,PASS
+readable-streams/templated.serviceworker.https.html,DISABLE
+readable-streams/templated.sharedworker.html,DISABLE
diff --git a/src/cobalt/layout_tests/web_platform_test_parser.cc b/src/cobalt/layout_tests/web_platform_test_parser.cc
index 21dc5ce..50b6c1e 100644
--- a/src/cobalt/layout_tests/web_platform_test_parser.cc
+++ b/src/cobalt/layout_tests/web_platform_test_parser.cc
@@ -23,6 +23,9 @@
 #include "base/string_util.h"
 #include "cobalt/base/cobalt_paths.h"
 #include "cobalt/layout_tests/test_utils.h"
+#include "cobalt/script/global_environment.h"
+#include "cobalt/script/javascript_engine.h"
+#include "cobalt/script/source_code.h"
 
 namespace cobalt {
 namespace layout_tests {
@@ -93,7 +96,34 @@
 }
 
 std::vector<WebPlatformTestInfo> EnumerateWebPlatformTests(
-    const std::string& top_level) {
+    const std::string& top_level, const char* precondition) {
+  if (precondition) {
+    // Evaluate the javascript precondition. Enumerate the web platform tests
+    // only if the precondition is true.
+    scoped_ptr<script::JavaScriptEngine> engine =
+        script::JavaScriptEngine::CreateEngine(
+            script::JavaScriptEngine::Options());
+    scoped_refptr<script::GlobalEnvironment> global_environment =
+        engine->CreateGlobalEnvironment();
+    global_environment->CreateGlobalObject();
+
+    std::string result;
+    bool success = global_environment->EvaluateScript(
+        script::SourceCode::CreateSourceCode(precondition,
+            base::SourceLocation(__FILE__, __LINE__, 1)),
+        &result);
+
+    if (!success) {
+      DLOG(ERROR) << "Failed to evaluate precondition: "
+                  << "\"" << precondition << "\"";
+      // Continue to enumerate tests like normal.
+    } else if (result != "true") {
+      DLOG(WARNING) << "Skipping Web Platform Tests for "
+                    << "\"" << top_level << "\"";
+      return std::vector<WebPlatformTestInfo>();
+    }
+  }
+
   FilePath test_dir(GetTestInputRootDirectory()
                         .Append("web-platform-tests")
                         .Append(top_level));
diff --git a/src/cobalt/layout_tests/web_platform_test_parser.h b/src/cobalt/layout_tests/web_platform_test_parser.h
index c46d84e..81577f5 100644
--- a/src/cobalt/layout_tests/web_platform_test_parser.h
+++ b/src/cobalt/layout_tests/web_platform_test_parser.h
@@ -51,8 +51,10 @@
                          const WebPlatformTestInfo& test_info);
 
 // Similar to EnumerateLayoutTests(), but reads web_platform_tests.txt
+// |precondition| may optionally be supplied. It represents a javascript
+//   expression which must return "true" for tests to be enumerated.
 std::vector<WebPlatformTestInfo> EnumerateWebPlatformTests(
-    const std::string& top_level);
+    const std::string& top_level, const char* precondition = NULL);
 
 }  // namespace layout_tests
 }  // namespace cobalt
diff --git a/src/cobalt/layout_tests/web_platform_tests.cc b/src/cobalt/layout_tests/web_platform_tests.cc
index 5794fa7..12e70e2 100644
--- a/src/cobalt/layout_tests/web_platform_tests.cc
+++ b/src/cobalt/layout_tests/web_platform_tests.cc
@@ -308,8 +308,18 @@
                         ::testing::ValuesIn(EnumerateWebPlatformTests("dom")));
 
 INSTANTIATE_TEST_CASE_P(
+    fetch, WebPlatformTest,
+    ::testing::ValuesIn(EnumerateWebPlatformTests("fetch",
+        "'fetch' in this")));
+
+INSTANTIATE_TEST_CASE_P(
     mediasession, WebPlatformTest,
     ::testing::ValuesIn(EnumerateWebPlatformTests("mediasession")));
+
+INSTANTIATE_TEST_CASE_P(
+    streams, WebPlatformTest,
+    ::testing::ValuesIn(EnumerateWebPlatformTests("streams",
+        "'ReadableStream' in this")));
 #endif  // !defined(COBALT_WIN)
 
 }  // namespace layout_tests
diff --git a/src/cobalt/media/base/drm_system.cc b/src/cobalt/media/base/drm_system.cc
index 639051f..bd41763 100644
--- a/src/cobalt/media/base/drm_system.cc
+++ b/src/cobalt/media/base/drm_system.cc
@@ -160,6 +160,13 @@
   } else {
     // Called back spontaneously by the underlying DRM system.
 
+    // Spontaneous calls must refer to a valid session.
+    if (!session_id) {
+      DLOG(FATAL) << "SbDrmSessionUpdateRequestFunc() should not be called "
+                     "with both invalid ticket and null session id.";
+      return;
+    }
+
     // Find the session by ID.
     IdToSessionMap::iterator session_iterator =
         id_to_session_map_.find(*session_id);
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index 4723e68..b0dae0b 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -423,6 +423,15 @@
   audio_header.average_bytes_per_second = 1;
   audio_header.block_alignment = 4;
   audio_header.bits_per_sample = audio_config_.bits_per_channel();
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  audio_header.audio_specific_config_size =
+      static_cast<uint16_t>(audio_config_.extra_data().size());
+  if (audio_header.audio_specific_config_size == 0) {
+    audio_header.audio_specific_config = NULL;
+  } else {
+    audio_header.audio_specific_config = &audio_config_.extra_data()[0];
+  }
+#else   // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
   audio_header.audio_specific_config_size = static_cast<uint16_t>(
       std::min(audio_config_.extra_data().size(),
                sizeof(audio_header.audio_specific_config)));
@@ -431,6 +440,7 @@
                  &audio_config_.extra_data()[0],
                  audio_header.audio_specific_config_size);
   }
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
 
   SbMediaAudioCodec audio_codec =
       MediaAudioCodecToSbMediaAudioCodec(audio_config_.codec());
diff --git a/src/cobalt/media/fetcher_buffered_data_source.cc b/src/cobalt/media/fetcher_buffered_data_source.cc
index 4ae7605..9dbdd5f 100644
--- a/src/cobalt/media/fetcher_buffered_data_source.cc
+++ b/src/cobalt/media/fetcher_buffered_data_source.cc
@@ -43,6 +43,7 @@
     : message_loop_(message_loop),
       url_(url),
       network_module_(network_module),
+      is_downloading_(false),
       buffer_(kInitialBufferCapacity, CircularBufferShell::kReserve),
       buffer_offset_(0),
       error_occured_(false),
@@ -110,6 +111,15 @@
   return *size_out != kInvalidSize;
 }
 
+void FetcherBufferedDataSource::SetDownloadingStatusCB(
+    const DownloadingStatusCB& downloading_status_cb) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  DCHECK(!downloading_status_cb.is_null());
+  DCHECK(downloading_status_cb_.is_null());
+  downloading_status_cb_ = downloading_status_cb;
+}
+
 void FetcherBufferedDataSource::OnURLFetchResponseStarted(
     const net::URLFetcher* source) {
   DCHECK(message_loop_->BelongsToCurrentThread());
@@ -194,6 +204,7 @@
     // stop the current request.
     fetcher_.reset();
     ProcessPendingRead_Locked();
+    UpdateDownloadingStatus(/* is_downloading = */ false);
     return;
   }
 
@@ -265,6 +276,7 @@
   fetcher_.reset();
 
   ProcessPendingRead_Locked();
+  UpdateDownloadingStatus(/* is_downloading = */ false);
 }
 
 void FetcherBufferedDataSource::CreateNewFetcher() {
@@ -285,6 +297,7 @@
     if (!pending_read_cb_.is_null()) {
       base::ResetAndReturn(&pending_read_cb_).Run(-1);
     }
+    UpdateDownloadingStatus(/* is_downloading = */ false);
     return;
   }
 
@@ -297,6 +310,20 @@
       base::Uint64ToString(last_request_offset_ + last_request_size_ - 1);
   fetcher_->AddExtraRequestHeader(range_request);
   fetcher_->Start();
+  UpdateDownloadingStatus(/* is_downloading = */ true);
+}
+
+void FetcherBufferedDataSource::UpdateDownloadingStatus(bool is_downloading) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  if (is_downloading_ == is_downloading) {
+    return;
+  }
+
+  is_downloading_ = is_downloading;
+  if (!downloading_status_cb_.is_null()) {
+    downloading_status_cb_.Run(is_downloading_);
+  }
 }
 
 void FetcherBufferedDataSource::Read_Locked(uint64 position, size_t size,
diff --git a/src/cobalt/media/fetcher_buffered_data_source.h b/src/cobalt/media/fetcher_buffered_data_source.h
index 1afea8c..29e7cce 100644
--- a/src/cobalt/media/fetcher_buffered_data_source.h
+++ b/src/cobalt/media/fetcher_buffered_data_source.h
@@ -81,6 +81,9 @@
   bool IsStreaming() OVERRIDE { return false; }
   void SetBitrate(int bitrate) OVERRIDE { UNREFERENCED_PARAMETER(bitrate); }
 
+  // BufferedDataSource methods.
+  void SetDownloadingStatusCB(const DownloadingStatusCB& downloading_status_cb);
+
  private:
   class CancelableClosure
       : public base::RefCountedThreadSafe<CancelableClosure> {
@@ -105,6 +108,7 @@
   void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   void CreateNewFetcher();
+  void UpdateDownloadingStatus(bool is_downloading);
   void Read_Locked(uint64 position, size_t size, uint8* data,
                    const ReadCB& read_cb);
   void ProcessPendingRead_Locked();
@@ -115,6 +119,10 @@
   GURL url_;
   network::NetworkModule* network_module_;
   scoped_ptr<net::URLFetcher> fetcher_;
+
+  bool is_downloading_;
+  DownloadingStatusCB downloading_status_cb_;
+
   // |fetcher_| has to be destroyed on the thread it's created.  So it cannot be
   // safely destroyed inside Read_Locked().  Save |fetcher_| into
   // |fetcher_to_be_destroyed_| to ensure that it is properly destroyed either
diff --git a/src/cobalt/media/player/buffered_data_source.h b/src/cobalt/media/player/buffered_data_source.h
index 9b75cb3..e9fac4f 100644
--- a/src/cobalt/media/player/buffered_data_source.h
+++ b/src/cobalt/media/player/buffered_data_source.h
@@ -16,6 +16,7 @@
 #define COBALT_MEDIA_PLAYER_BUFFERED_DATA_SOURCE_H_
 
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/message_loop.h"
 #include "cobalt/media/base/data_source.h"
 #include "googleurl/src/gurl.h"
@@ -33,6 +34,12 @@
 // TODO: Investigate if we still need BufferedDataSource.
 class BufferedDataSource : public DataSource {
  public:
+  typedef base::Callback<void(bool)> DownloadingStatusCB;
+
+  virtual void SetDownloadingStatusCB(
+      const DownloadingStatusCB& downloading_status_cb) {
+    UNREFERENCED_PARAMETER(downloading_status_cb);
+  }
   virtual void SetPreload(Preload preload) { UNREFERENCED_PARAMETER(preload); }
   virtual bool HasSingleOrigin() { return true; }
   virtual bool DidPassCORSAccessCheck() const { return true; }
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index d145b6a..623c892 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -249,6 +249,8 @@
   SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
   media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
 
+  data_source->SetDownloadingStatusCB(
+      base::Bind(&WebMediaPlayerImpl::OnDownloadingStatusChanged, AsWeakPtr()));
   proxy_->set_data_source(data_source.Pass());
 
   is_local_source_ = !url.SchemeIs("http") && !url.SchemeIs("https");
@@ -670,7 +672,7 @@
   GetClient()->SetOpaque(opaque);
 }
 
-void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
+void WebMediaPlayerImpl::OnDownloadingStatusChanged(bool is_downloading) {
   if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
     SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
   else if (is_downloading &&
diff --git a/src/cobalt/media/player/web_media_player_impl.h b/src/cobalt/media/player/web_media_player_impl.h
index 3babef5..5f3477b 100644
--- a/src/cobalt/media/player/web_media_player_impl.h
+++ b/src/cobalt/media/player/web_media_player_impl.h
@@ -194,7 +194,7 @@
 
  private:
   // Called when the data source is downloading or paused.
-  void NotifyDownloading(bool is_downloading);
+  void OnDownloadingStatusChanged(bool is_downloading);
 
   // Finishes starting the pipeline due to a call to load().
   void StartPipeline(Demuxer* demuxer);
diff --git a/src/cobalt/network/starboard/user_agent_string_factory_starboard.cc b/src/cobalt/network/starboard/user_agent_string_factory_starboard.cc
index 867e7ab..7a2ddd2 100644
--- a/src/cobalt/network/starboard/user_agent_string_factory_starboard.cc
+++ b/src/cobalt/network/starboard/user_agent_string_factory_starboard.cc
@@ -25,6 +25,14 @@
 
 namespace {
 
+#if SB_API_VERSION == SB_EXPERIMENTAL_API_VERSION
+const char kStarboardStabilitySuffix[] = "-Experimental";
+#elif SB_API_VERSION == SB_RELEASE_CANDIDATE_API_VERSION
+const char kStarboardStabilitySuffix[] = "-ReleaseCandidate";
+#else
+const char kStarboardStabilitySuffix[] = "";
+#endif
+
 bool SystemDeviceTypeIsTv(SbSystemDeviceType device_type) {
   switch (device_type) {
     case kSbSystemDeviceTypeBlueRayDiskPlayer:
@@ -49,7 +57,8 @@
 };
 
 UserAgentStringFactoryStarboard::UserAgentStringFactoryStarboard() {
-  starboard_version_ = base::StringPrintf("Starboard/%d", SB_API_VERSION);
+  starboard_version_ = base::StringPrintf("Starboard/%d%s", SB_API_VERSION,
+                                          kStarboardStabilitySuffix);
 
   const size_t kSystemPropertyMaxLength = 1024;
   char value[kSystemPropertyMaxLength];
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_distance_field_texture.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_distance_field_texture.glsl
index 432a143..ac6d8f4 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_distance_field_texture.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_distance_field_texture.glsl
@@ -15,7 +15,7 @@
     vec2 uv = vtextureCoords_Stage0;

     vec2 st = uv*uTextureSize_Stage0;

     float afwidth;

-    afwidth = 0.7071*dFdx(st.x);

+    afwidth = abs(0.7071*dFdy(st.y));

     float val = smoothstep(-afwidth, afwidth, distance);

     output_Stage0 = vec4(val);

   }

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_rgba.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_rgba.glsl
new file mode 100644
index 0000000..4400f4b
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_rgba.glsl
@@ -0,0 +1,9 @@
+precision mediump float;

+varying vec2 v_tex_coord_rgba;

+uniform sampler2D texture_rgba;

+uniform mat4 to_rgb_color_matrix;

+

+void main() {

+  vec4 untransformed_color = vec4(texture2D(texture_rgba, v_tex_coord_rgba).rgba);

+  gl_FragColor = untransformed_color * to_rgb_color_matrix;

+}
\ No newline at end of file
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_2plane.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_2plane.glsl
new file mode 100644
index 0000000..75b5036
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_2plane.glsl
@@ -0,0 +1,14 @@
+precision mediump float;

+varying vec2 v_tex_coord_y;

+varying vec2 v_tex_coord_uv;

+uniform sampler2D texture_y;

+uniform sampler2D texture_uv;

+uniform mat4 to_rgb_color_matrix;

+

+void main() {

+  vec4 untransformed_color = vec4(

+      texture2D(texture_y, v_tex_coord_y).a,

+      texture2D(texture_uv, v_tex_coord_uv).ba, 1.0);

+

+  gl_FragColor = untransformed_color * to_rgb_color_matrix;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_3plane.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_3plane.glsl
new file mode 100644
index 0000000..91137c6
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_textured_vbo_yuv_3plane.glsl
@@ -0,0 +1,15 @@
+precision mediump float;

+varying vec2 v_tex_coord_y;

+varying vec2 v_tex_coord_u;

+varying vec2 v_tex_coord_v;

+uniform sampler2D texture_y;

+uniform sampler2D texture_u;

+uniform sampler2D texture_v;

+uniform mat4 to_rgb_color_matrix;

+void main() {

+  vec4 untransformed_color = vec4(

+    texture2D(texture_y, v_tex_coord_y).a,

+    texture2D(texture_u, v_tex_coord_u).a,

+    texture2D(texture_v, v_tex_coord_v).a, 1.0);

+  gl_FragColor = untransformed_color * to_rgb_color_matrix;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi b/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
index 2740656..1467215 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
+++ b/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
@@ -79,6 +79,9 @@
       'fragment_skia_texture_domain_masked_texture_domain.glsl',
       'fragment_skia_texture_masked_texture.glsl',
       'fragment_skia_yuv.glsl',
+      'fragment_textured_vbo_rgba.glsl',
+      'fragment_textured_vbo_yuv_2plane.glsl',
+      'fragment_textured_vbo_yuv_3plane.glsl',
       'vertex_mesh.glsl',
       'vertex_position_and_texcoord.glsl',
       'vertex_skia_antialiased_circle.glsl',
@@ -93,6 +96,9 @@
       'vertex_skia_two_texcoords_and_color_with_texcoord_matrices.glsl',
       'vertex_skia_two_texcoords_derived_from_position.glsl',
       'vertex_skia_yuv.glsl',
+      'vertex_textured_vbo_rgba.glsl',
+      'vertex_textured_vbo_yuv_2plane.glsl',
+      'vertex_textured_vbo_yuv_3plane.glsl',
     ],
   }
 }
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_rgba.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_rgba.glsl
new file mode 100644
index 0000000..5797b87
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_rgba.glsl
@@ -0,0 +1,11 @@
+attribute vec3 a_position;

+attribute vec2 a_tex_coord;

+varying vec2 v_tex_coord_rgba;

+uniform vec4 scale_translate_rgba;

+uniform mat4 model_view_projection_transform;

+

+void main() {

+  gl_Position = model_view_projection_transform * vec4(a_position.xyz, 1.0);

+  v_tex_coord_rgba =

+      a_tex_coord * scale_translate_rgba.xy + scale_translate_rgba.zw;

+}
\ No newline at end of file
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_2plane.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_2plane.glsl
new file mode 100644
index 0000000..8ebde52
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_2plane.glsl
@@ -0,0 +1,13 @@
+attribute vec3 a_position;

+attribute vec2 a_tex_coord;

+varying vec2 v_tex_coord_y;

+varying vec2 v_tex_coord_uv;

+uniform vec4 scale_translate_y;

+uniform vec4 scale_translate_uv;

+uniform mat4 model_view_projection_transform;

+

+void main() {

+  gl_Position = model_view_projection_transform * vec4(a_position.xyz, 1.0);

+  v_tex_coord_y = a_tex_coord * scale_translate_y.xy + scale_translate_y.zw;

+  v_tex_coord_uv = a_tex_coord * scale_translate_uv.xy + scale_translate_uv.zw;

+}
\ No newline at end of file
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_3plane.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_3plane.glsl
new file mode 100644
index 0000000..c95ad67
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_textured_vbo_yuv_3plane.glsl
@@ -0,0 +1,16 @@
+attribute vec3 a_position;

+attribute vec2 a_tex_coord;

+varying vec2 v_tex_coord_y;

+varying vec2 v_tex_coord_u;

+varying vec2 v_tex_coord_v;

+uniform vec4 scale_translate_y;

+uniform vec4 scale_translate_u;

+uniform vec4 scale_translate_v;

+uniform mat4 model_view_projection_transform;

+

+void main() {

+  gl_Position = model_view_projection_transform * vec4(a_position.xyz, 1.0);

+  v_tex_coord_y = a_tex_coord * scale_translate_y.xy + scale_translate_y.zw;

+  v_tex_coord_u = a_tex_coord * scale_translate_u.xy + scale_translate_u.zw;

+  v_tex_coord_v = a_tex_coord * scale_translate_v.xy + scale_translate_v.zw;

+}
\ No newline at end of file
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
index 2315836..86c471b 100644
--- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
@@ -96,6 +96,7 @@
     SbDecodeTargetDestroy(decode_target);
     return make_scoped_refptr(
         new SinglePlaneImage(surface, is_opaque, base::Closure()));
+  }
 #else   // SB_API_VERSION < 4
   SbDecodeTargetInfo info;
   SbMemorySet(&info, 0, sizeof(info));
@@ -115,8 +116,8 @@
     return make_scoped_refptr(new SinglePlaneImage(
         plane.surface, info.is_opaque,
         base::Bind(&SbDecodeTargetRelease, decode_target)));
-#endif  // SB_API_VERSION < 4
   }
+#endif  // SB_API_VERSION < 4
 
   NOTREACHED()
       << "Only format kSbDecodeTargetFormat1PlaneRGBA is currently supported.";
diff --git a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
index 8f932a9..2cd58c0 100644
--- a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
@@ -18,7 +18,9 @@
 #include <GLES2/gl2ext.h>
 
 #include <string>
+#include <vector>
 
+#include "base/stringprintf.h"
 #include "cobalt/math/size.h"
 #include "cobalt/renderer/backend/egl/utils.h"
 #include "third_party/glm/glm/gtc/type_ptr.hpp"
@@ -37,9 +39,8 @@
   if (quad_vbo_) {
     GL_CALL(glDeleteBuffers(1, &quad_vbo_.value()));
   }
-  for (std::map<uint32, ProgramInfo>::iterator iter =
-           blit_program_per_texture_target_.begin();
-       iter != blit_program_per_texture_target_.end(); ++iter) {
+  for (ProgramCache::iterator iter = blit_program_cache_.begin();
+       iter != blit_program_cache_.end(); ++iter) {
     GL_CALL(glDeleteProgram(iter->second.gl_program_id));
   }
 }
@@ -71,13 +72,39 @@
   out_vec4[2] = translate_x;
   out_vec4[3] = translate_y;
 }
+
+// Used for RGB images.
+const float kIdentityColorMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+                                        0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+                                        0.0f, 0.0f, 0.0f, 1.0f};
+
+// Used for YUV images.
+const float kBT709ColorMatrix[16] = {
+    1.164f, 0.0f,   1.793f, -0.96925f, 1.164f, -0.213f, -0.533f, 0.30025f,
+    1.164f, 2.112f, 0.0f,   -1.12875f, 0.0f,   0.0f,    0.0f,    1.0};
+
+const float* GetColorMatrixForImageType(
+    TexturedMeshRenderer::Image::Type type) {
+  switch (type) {
+    case TexturedMeshRenderer::Image::RGBA: {
+      return kIdentityColorMatrix;
+    } break;
+    case TexturedMeshRenderer::Image::YUV_2PLANE_BT709:
+    case TexturedMeshRenderer::Image::YUV_3PLANE_BT709: {
+      return kBT709ColorMatrix;
+    } break;
+    default: { NOTREACHED(); }
+  }
+  return NULL;
+}
+
 }  // namespace
 
 void TexturedMeshRenderer::RenderVBO(uint32 vbo, int num_vertices, uint32 mode,
-                                     const backend::TextureEGL* texture,
-                                     const math::Rect& content_region,
+                                     const Image& image,
                                      const glm::mat4& mvp_transform) {
-  ProgramInfo blit_program = GetBlitProgram(texture->GetTarget());
+  ProgramInfo blit_program =
+      GetBlitProgram(image.type, image.textures[0].texture->GetTarget());
 
   GL_CALL(glUseProgram(blit_program.gl_program_id));
 
@@ -90,32 +117,42 @@
   GL_CALL(glEnableVertexAttribArray(kBlitPositionAttribute));
   GL_CALL(glEnableVertexAttribArray(kBlitTexcoordAttribute));
 
-  GL_CALL(glActiveTexture(GL_TEXTURE0));
-  GL_CALL(glBindTexture(texture->GetTarget(), texture->gl_handle()));
-
   GL_CALL(glUniformMatrix4fv(blit_program.mvp_transform_uniform, 1, GL_FALSE,
                              glm::value_ptr(mvp_transform)));
 
-  float scale_translate_vector[4];
-  ConvertContentRegionToScaleTranslateVector(
-      &content_region, texture->GetSize(), scale_translate_vector);
-  GL_CALL(glUniform4fv(blit_program.texcoord_scale_translate_uniform, 1,
-                       scale_translate_vector));
+  for (int i = 0; i < image.num_textures(); ++i) {
+    DCHECK_EQ(image.textures[0].texture->GetTarget(),
+              image.textures[i].texture->GetTarget());
+
+    GL_CALL(glActiveTexture(GL_TEXTURE0 + i));
+    GL_CALL(glBindTexture(image.textures[i].texture->GetTarget(),
+                          image.textures[i].texture->gl_handle()));
+
+    GL_CALL(glUniform1i(blit_program.texture_uniforms[i], i));
+
+    float scale_translate_vector[4];
+    ConvertContentRegionToScaleTranslateVector(
+        &image.textures[i].content_region, image.textures[i].texture->GetSize(),
+        scale_translate_vector);
+    GL_CALL(glUniform4fv(blit_program.texcoord_scale_translate_uniforms[i], 1,
+                         scale_translate_vector));
+  }
 
   GL_CALL(glDrawArrays(mode, 0, num_vertices));
 
-  GL_CALL(glBindTexture(texture->GetTarget(), 0));
+  for (int i = 0; i < image.num_textures(); ++i) {
+    GL_CALL(glActiveTexture(GL_TEXTURE0 + i));
+    GL_CALL(glBindTexture(image.textures[i].texture->GetTarget(), 0));
+  }
 
   GL_CALL(glDisableVertexAttribArray(kBlitTexcoordAttribute));
   GL_CALL(glDisableVertexAttribArray(kBlitPositionAttribute));
   GL_CALL(glUseProgram(0));
 }
 
-void TexturedMeshRenderer::RenderQuad(const backend::TextureEGL* texture,
-                                      const math::Rect& content_region,
+void TexturedMeshRenderer::RenderQuad(const Image& image,
                                       const glm::mat4& mvp_transform) {
-  RenderVBO(GetQuadVBO(), 4, GL_TRIANGLE_STRIP, texture, content_region,
-            mvp_transform);
+  RenderVBO(GetQuadVBO(), 4, GL_TRIANGLE_STRIP, image, mvp_transform);
 }
 
 uint32 TexturedMeshRenderer::GetQuadVBO() {
@@ -131,8 +168,8 @@
     };
     const QuadVertex kBlitQuadVerts[4] = {
         {-1.0f, -1.0f, 0.0f, 0.0f, 0.0f},
-        {-1.0f, 1.0f, 0.0f, 0.0f, 1.0f},
         {1.0f, -1.0f, 0.0f, 1.0f, 0.0f},
+        {-1.0f, 1.0f, 0.0f, 0.0f, 1.0f},
         {1.0f, 1.0, 0.0f, 1.0f, 1.0f},
     };
 
@@ -146,97 +183,193 @@
   return *quad_vbo_;
 }
 
+// static
+uint32 TexturedMeshRenderer::CreateVertexShader(
+    const std::vector<TextureInfo>& textures) {
+  uint32 blit_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+  std::string blit_vertex_shader_source =
+      "attribute vec3 a_position;"
+      "attribute vec2 a_tex_coord;";
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    blit_vertex_shader_source +=
+        StringPrintf("varying vec2 v_tex_coord_%s;", textures[i].name.c_str());
+  }
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    blit_vertex_shader_source += StringPrintf(
+        "uniform vec4 scale_translate_%s;", textures[i].name.c_str());
+  }
+  blit_vertex_shader_source +=
+      "uniform mat4 model_view_projection_transform;"
+      "void main() {"
+      "  gl_Position = model_view_projection_transform * "
+      "                    vec4(a_position.xyz, 1.0);";
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    const char* texture_name = textures[i].name.c_str();
+    blit_vertex_shader_source += StringPrintf(
+        "  v_tex_coord_%s = "
+        "      a_tex_coord * scale_translate_%s.xy + scale_translate_%s.zw;",
+        texture_name, texture_name, texture_name);
+  }
+  blit_vertex_shader_source += "}";
+
+  int blit_vertex_shader_source_length = blit_vertex_shader_source.size();
+  const char* blit_vertex_shader_source_c_str =
+      blit_vertex_shader_source.c_str();
+  GL_CALL(glShaderSource(blit_vertex_shader, 1,
+                         &blit_vertex_shader_source_c_str,
+                         &blit_vertex_shader_source_length));
+  GL_CALL(glCompileShader(blit_vertex_shader));
+
+  return blit_vertex_shader;
+}
+
+// static
+uint32 TexturedMeshRenderer::CreateFragmentShader(
+    uint32 texture_target, const std::vector<TextureInfo>& textures) {
+  uint32 blit_fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+  std::string sampler_type = "sampler2D";
+  std::string blit_fragment_shader_source;
+
+  if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
+    sampler_type = "samplerExternalOES";
+    blit_fragment_shader_source +=
+        "#extension GL_OES_EGL_image_external : require\n";
+  }
+
+  blit_fragment_shader_source += "precision mediump float;";
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    blit_fragment_shader_source +=
+        StringPrintf("varying vec2 v_tex_coord_%s;", textures[i].name.c_str());
+  }
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    blit_fragment_shader_source +=
+        StringPrintf("uniform %s texture_%s;", sampler_type.c_str(),
+                     textures[i].name.c_str());
+  }
+  blit_fragment_shader_source +=
+      "uniform mat4 to_rgb_color_matrix;"
+      "void main() {"
+      "  vec4 untransformed_color = vec4(";
+  int components_used = 0;
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    if (i > 0) {
+      blit_fragment_shader_source += ", ";
+    }
+    blit_fragment_shader_source += StringPrintf(
+        "texture2D(texture_%s, v_tex_coord_%s).%s", textures[i].name.c_str(),
+        textures[i].name.c_str(), textures[i].components.c_str());
+    components_used += textures[i].components.length();
+  }
+  if (components_used == 3) {
+    // Add an alpha component of 1.
+    blit_fragment_shader_source += ", 1.0";
+  }
+  blit_fragment_shader_source +=
+      ");"
+      "  gl_FragColor = untransformed_color * to_rgb_color_matrix;"
+      "}";
+
+  int blit_fragment_shader_source_length = blit_fragment_shader_source.size();
+  const char* blit_fragment_shader_source_c_str =
+      blit_fragment_shader_source.c_str();
+  GL_CALL(glShaderSource(blit_fragment_shader, 1,
+                         &blit_fragment_shader_source_c_str,
+                         &blit_fragment_shader_source_length));
+  GL_CALL(glCompileShader(blit_fragment_shader));
+
+  return blit_fragment_shader;
+}
+
+// static
+TexturedMeshRenderer::ProgramInfo TexturedMeshRenderer::MakeBlitProgram(
+    const float* color_matrix, uint32 texture_target,
+    const std::vector<TextureInfo>& textures) {
+  int total_components = 0;
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    total_components += textures[i].components.length();
+  }
+  DCHECK(total_components == 3 || total_components == 4);
+
+  ProgramInfo result;
+
+  // Create the blit program.
+  // Setup shaders used when blitting the current texture.
+  result.gl_program_id = glCreateProgram();
+
+  uint32 blit_vertex_shader = CreateVertexShader(textures);
+  GL_CALL(glAttachShader(result.gl_program_id, blit_vertex_shader));
+
+  uint32 blit_fragment_shader = CreateFragmentShader(texture_target, textures);
+  GL_CALL(glAttachShader(result.gl_program_id, blit_fragment_shader));
+
+  GL_CALL(glBindAttribLocation(result.gl_program_id, kBlitPositionAttribute,
+                               "a_position"));
+  GL_CALL(glBindAttribLocation(result.gl_program_id, kBlitTexcoordAttribute,
+                               "a_tex_coord"));
+
+  GL_CALL(glLinkProgram(result.gl_program_id));
+
+  result.mvp_transform_uniform = glGetUniformLocation(
+      result.gl_program_id, "model_view_projection_transform");
+  for (unsigned int i = 0; i < textures.size(); ++i) {
+    std::string scale_translate_uniform_name =
+        StringPrintf("scale_translate_%s", textures[i].name.c_str());
+    result.texcoord_scale_translate_uniforms[i] = glGetUniformLocation(
+        result.gl_program_id, scale_translate_uniform_name.c_str());
+
+    std::string texture_uniform_name =
+        StringPrintf("texture_%s", textures[i].name.c_str());
+    result.texture_uniforms[i] = glGetUniformLocation(
+        result.gl_program_id, texture_uniform_name.c_str());
+  }
+
+  // Upload the color matrix right away since it won't change from draw to draw.
+  GL_CALL(glUseProgram(result.gl_program_id));
+  uint32 to_rgb_color_matrix_uniform =
+      glGetUniformLocation(result.gl_program_id, "to_rgb_color_matrix");
+  GL_CALL(glUniformMatrix4fv(to_rgb_color_matrix_uniform, 1, GL_FALSE,
+                             color_matrix));
+  GL_CALL(glUseProgram(0));
+
+  GL_CALL(glDeleteShader(blit_fragment_shader));
+  GL_CALL(glDeleteShader(blit_vertex_shader));
+
+  return result;
+}
+
 TexturedMeshRenderer::ProgramInfo TexturedMeshRenderer::GetBlitProgram(
-    uint32 texture_target) {
-  std::map<uint32, ProgramInfo>::iterator found =
-      blit_program_per_texture_target_.find(texture_target);
-  if (found == blit_program_per_texture_target_.end()) {
+    Image::Type type, uint32 texture_target) {
+  CacheKey key(texture_target, type);
+
+  ProgramCache::iterator found = blit_program_cache_.find(key);
+  if (found == blit_program_cache_.end()) {
+    const float* color_matrix = GetColorMatrixForImageType(type);
     ProgramInfo result;
-
-    // Create the blit program.
-    // Setup shaders used when blitting the current texture.
-    result.gl_program_id = glCreateProgram();
-
-    uint32 blit_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
-    const char* blit_vertex_shader_source =
-        "attribute vec3 a_position;"
-        "attribute vec2 a_tex_coord;"
-        "varying vec2 v_tex_coord;"
-        "uniform vec4 scale_translate;"
-        "uniform mat4 model_view_projection_transform;"
-        "void main() {"
-        "  gl_Position = model_view_projection_transform * "
-        "                    vec4(a_position.xyz, 1.0);"
-        "  v_tex_coord = "
-        "      a_tex_coord * scale_translate.xy + scale_translate.zw;"
-        "}";
-    int blit_vertex_shader_source_length = strlen(blit_vertex_shader_source);
-    GL_CALL(glShaderSource(blit_vertex_shader, 1, &blit_vertex_shader_source,
-                           &blit_vertex_shader_source_length));
-    GL_CALL(glCompileShader(blit_vertex_shader));
-
-    char buffer[2048];
-    int length;
-    glGetShaderInfoLog(blit_vertex_shader, 2048, &length, buffer);
-    DLOG(INFO) << "vertex shader: " << buffer;
-
-    GL_CALL(glAttachShader(result.gl_program_id, blit_vertex_shader));
-
-    std::string sampler_type = "sampler2D";
-    if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
-      sampler_type = "samplerExternalOES";
+    switch (type) {
+      case Image::RGBA: {
+        std::vector<TextureInfo> texture_infos;
+        texture_infos.push_back(TextureInfo("rgba", "rgba"));
+        result = MakeBlitProgram(color_matrix, texture_target, texture_infos);
+      } break;
+      case Image::YUV_2PLANE_BT709: {
+        std::vector<TextureInfo> texture_infos;
+        texture_infos.push_back(TextureInfo("y", "a"));
+        texture_infos.push_back(TextureInfo("uv", "ba"));
+        result = MakeBlitProgram(color_matrix, texture_target, texture_infos);
+      } break;
+      case Image::YUV_3PLANE_BT709: {
+        std::vector<TextureInfo> texture_infos;
+        texture_infos.push_back(TextureInfo("y", "a"));
+        texture_infos.push_back(TextureInfo("u", "a"));
+        texture_infos.push_back(TextureInfo("v", "a"));
+        result = MakeBlitProgram(color_matrix, texture_target, texture_infos);
+      } break;
+      default: { NOTREACHED(); }
     }
-    uint32 blit_fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
-    std::string blit_fragment_shader_source =
-        "precision mediump float;"
-        "varying vec2 v_tex_coord;"
-        "uniform " +
-        sampler_type +
-        " texture;"
-        "void main() {"
-        "  gl_FragColor = texture2D(texture, v_tex_coord);"
-        "}";
-    if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
-      blit_fragment_shader_source =
-          "#extension GL_OES_EGL_image_external : require\n" +
-          blit_fragment_shader_source;
-    }
-
-    int blit_fragment_shader_source_length = blit_fragment_shader_source.size();
-    const char* blit_fragment_shader_source_c_str =
-        blit_fragment_shader_source.c_str();
-    GL_CALL(glShaderSource(blit_fragment_shader, 1,
-                           &blit_fragment_shader_source_c_str,
-                           &blit_fragment_shader_source_length));
-    GL_CALL(glCompileShader(blit_fragment_shader));
-
-    glGetShaderInfoLog(blit_fragment_shader, 2048, &length, buffer);
-    DLOG(INFO) << "fragment shader: " << buffer;
-
-    GL_CALL(glAttachShader(result.gl_program_id, blit_fragment_shader));
-
-    GL_CALL(glBindAttribLocation(result.gl_program_id, kBlitPositionAttribute,
-                                 "a_position"));
-    GL_CALL(glBindAttribLocation(result.gl_program_id, kBlitTexcoordAttribute,
-                                 "a_tex_coord"));
-
-    GL_CALL(glLinkProgram(result.gl_program_id));
-
-    glGetProgramInfoLog(result.gl_program_id, 2048, &length, buffer);
-    DLOG(INFO) << buffer;
-
-    result.mvp_transform_uniform = glGetUniformLocation(
-        result.gl_program_id, "model_view_projection_transform");
-    result.texcoord_scale_translate_uniform =
-        glGetUniformLocation(result.gl_program_id, "scale_translate");
-
-    GL_CALL(glDeleteShader(blit_fragment_shader));
-    GL_CALL(glDeleteShader(blit_vertex_shader));
 
     // Save our shader into the cache.
-    found = blit_program_per_texture_target_.insert(std::make_pair(
-                                                        texture_target, result))
-                .first;
+    found = blit_program_cache_.insert(std::make_pair(key, result)).first;
   }
 
   return found->second;
diff --git a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.h b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.h
index 5794920..dd3efae 100644
--- a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.h
+++ b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.h
@@ -16,6 +16,9 @@
 #define COBALT_RENDERER_RASTERIZER_EGL_TEXTURED_MESH_RENDERER_H_
 
 #include <map>
+#include <string>
+#include <utility>
+#include <vector>
 
 #include "base/optional.h"
 #include "cobalt/math/rect.h"
@@ -37,42 +40,92 @@
   explicit TexturedMeshRenderer(backend::GraphicsContextEGL* graphics_context);
   ~TexturedMeshRenderer();
 
+  // The Image structure acts as an interface for describing an image, which
+  // in the case of YUV formats, may be composed of multiple textures.
+  struct Image {
+    enum Type {
+      // YUV BT709 image, where the Y component is on one plane and the UV
+      // components are on a second plane.  NV12 would for example choose
+      // this format type.
+      YUV_2PLANE_BT709,
+      // YUV BT709 image where the Y, U and V components are all on different
+      // textures.
+      YUV_3PLANE_BT709,
+      RGBA,  // 1 texture is used that contains RGBA pixels.
+    };
+
+    struct Texture {
+      const backend::TextureEGL* texture;
+      math::Rect content_region;
+    };
+
+    // Returns the number of valid textures in this image, based on its format.
+    int num_textures() const {
+      switch (type) {
+        case YUV_2PLANE_BT709:
+          return 2;
+        case YUV_3PLANE_BT709:
+          return 3;
+        case RGBA:
+          return 1;
+        default:
+          NOTREACHED();
+      }
+      return 0;
+    }
+
+    Type type;
+    Texture textures[3];
+  };
+
   // A context must be current before this method is called.  Before calling
   // this function, please configure glViewport() and glScissor() as desired.
   // The content region indicates which source rectangle of the input texture
   // should be used (i.e. the VBO's texture coordinates will be transformed to
   // lie within this rectangle).
-  void RenderVBO(uint32 vbo, int num_vertices, uint32 mode,
-                 const backend::TextureEGL* texture,
-                 const math::Rect& content_region,
+  void RenderVBO(uint32 vbo, int num_vertices, uint32 mode, const Image& image,
                  const glm::mat4& mvp_transform);
 
   // This method will call into RenderVBO(), so the comments pertaining to that
   // method also apply to this method.  This method renders with vertex
   // positions (-1, -1) -> (1, 1), so it will occupy the entire viewport
   // specified by glViewport().
-  void RenderQuad(const backend::TextureEGL* texture,
-                  const math::Rect& content_region,
-                  const glm::mat4& mvp_transform);
+  void RenderQuad(const Image& image, const glm::mat4& mvp_transform);
 
  private:
+  struct TextureInfo {
+    TextureInfo(const std::string& name, const std::string& components)
+        : name(name), components(components) {}
+
+    std::string name;
+    std::string components;
+  };
   struct ProgramInfo {
     uint32 mvp_transform_uniform;
-    uint32 texcoord_scale_translate_uniform;
+    uint32 texcoord_scale_translate_uniforms[3];
+    uint32 texture_uniforms[3];
     uint32 gl_program_id;
   };
-  typedef std::map<uint32, ProgramInfo> ProgramMap;
+  // We key each program off of their GL texture type and image type.
+  typedef std::pair<uint32, Image::Type> CacheKey;
+  typedef std::map<CacheKey, ProgramInfo> ProgramCache;
 
   uint32 GetQuadVBO();
-  ProgramInfo GetBlitProgram(uint32 texture_target);
+  ProgramInfo GetBlitProgram(Image::Type type, uint32 texture_target);
 
+  static ProgramInfo MakeBlitProgram(const float* color_matrix,
+                                     uint32 texture_target,
+                                     const std::vector<TextureInfo>& textures);
+  static uint32 CreateFragmentShader(uint32 texture_target,
+                                     const std::vector<TextureInfo>& textures);
+  static uint32 CreateVertexShader(const std::vector<TextureInfo>& textures);
 
   backend::GraphicsContextEGL* graphics_context_;
 
   // Since different texture targets can warrant different shaders/programs,
   // we keep a map of blit programs for each texture target, and initialize
   // them lazily.
-  ProgramMap blit_program_per_texture_target_;
+  ProgramCache blit_program_cache_;
 
   static const int kBlitPositionAttribute = 0;
   static const int kBlitTexcoordAttribute = 1;
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
index 5ce02f6..ed7062f 100644
--- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
@@ -31,11 +31,9 @@
 
 class ExternalRasterizer::Impl {
  public:
-  Impl(backend::GraphicsContext* graphics_context,
-       int skia_atlas_width, int skia_atlas_height,
-       int skia_cache_size_in_bytes,
-       int scratch_surface_cache_size_in_bytes,
-       int surface_cache_size_in_bytes,
+  Impl(backend::GraphicsContext* graphics_context, int skia_atlas_width,
+       int skia_atlas_height, int skia_cache_size_in_bytes,
+       int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
        bool purge_skia_font_caches_on_destruction);
   ~Impl();
 
@@ -68,11 +66,10 @@
     : graphics_context_(
           base::polymorphic_downcast<backend::GraphicsContextEGL*>(
               graphics_context)),
-      hardware_rasterizer_(graphics_context, skia_atlas_width,
-                           skia_atlas_height, skia_cache_size_in_bytes,
-                           scratch_surface_cache_size_in_bytes,
-                           surface_cache_size_in_bytes,
-                           purge_skia_font_caches_on_destruction) {
+      hardware_rasterizer_(
+          graphics_context, skia_atlas_width, skia_atlas_height,
+          skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
+          surface_cache_size_in_bytes, purge_skia_font_caches_on_destruction) {
   options_.flags = skia::HardwareRasterizer::kSubmitFlags_Clear;
   graphics_context_->MakeCurrent();
 
@@ -93,11 +90,18 @@
 void ExternalRasterizer::Impl::Submit(
     const scoped_refptr<render_tree::Node>& render_tree,
     const scoped_refptr<backend::RenderTarget>& render_target) {
-  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-  glClear(0);
   backend::RenderTargetEGL* render_target_egl =
       base::polymorphic_downcast<backend::RenderTargetEGL*>(
           render_target.get());
+  // When the provided RenderTarget is not a window RenderTarget, then this
+  // implies the rasterized RenderTree should not be shown directly to the user
+  // and thus should not be rasterized into a texture and sent through to the
+  // client implementing CbLibRenderFrame.
+  if (!render_target_egl->IsWindowRenderTarget()) {
+    hardware_rasterizer_.Submit(render_tree, render_target, options_);
+    return;
+  }
+
   graphics_context_->MakeCurrentWithSurface(render_target_egl);
 
   backend::RenderTargetEGL* main_texture_render_target_egl =
@@ -107,10 +111,10 @@
                               options_);
 
   const intptr_t texture_handle = main_texture_->GetPlatformHandle();
-  // TODO: Provide mesh data to clients for map-to-mesh playbacks and a separate
-  // video texture handle.
-  // TODO: Allow clients to specify arbitrary subtrees to render into different
-  // textures?
+  // TODO: Provide mesh data to clients for map-to-mesh playbacks and a
+  // separate video texture handle.
+  // TODO: Allow clients to specify arbitrary subtrees to render into
+  // different textures?
   CbLibRenderFrame(texture_handle);
 
   graphics_context_->SwapBuffers(render_target_egl);
@@ -125,11 +129,11 @@
     int skia_atlas_height, int skia_cache_size_in_bytes,
     int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
     bool purge_skia_font_caches_on_destruction)
-    : impl_(new Impl(graphics_context, skia_atlas_width, skia_atlas_height,
-                     skia_cache_size_in_bytes,
-                     scratch_surface_cache_size_in_bytes,
-                     surface_cache_size_in_bytes,
-                     purge_skia_font_caches_on_destruction)) {}
+    : impl_(new Impl(
+          graphics_context, skia_atlas_width, skia_atlas_height,
+          skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
+          surface_cache_size_in_bytes, purge_skia_font_caches_on_destruction)) {
+}
 
 ExternalRasterizer::~ExternalRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index cc16d83..fb95695 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -30,6 +30,7 @@
 #include "cobalt/render_tree/glyph_buffer.h"
 #include "cobalt/render_tree/image.h"
 #include "cobalt/render_tree/image_node.h"
+#include "cobalt/render_tree/matrix_transform_3d_node.h"
 #include "cobalt/render_tree/matrix_transform_node.h"
 #include "cobalt/render_tree/punch_through_video_node.h"
 #include "cobalt/render_tree/rect_node.h"
@@ -40,6 +41,8 @@
 #include "cobalt/render_tree/typeface.h"
 #include "cobalt/renderer/rasterizer/pixel_test_fixture.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/glm/glm/gtc/matrix_transform.hpp"
+#include "third_party/glm/glm/gtx/transform.hpp"
 
 #define BILINEAR_FILTERING_SUPPORTED 1
 #define NV12_TEXTURE_SUPPORTED 1
@@ -86,7 +89,10 @@
 using cobalt::render_tree::ImageDataDescriptor;
 using cobalt::render_tree::ImageNode;
 using cobalt::render_tree::LinearGradientBrush;
+using cobalt::render_tree::MapToMeshFilter;
+using cobalt::render_tree::MatrixTransform3DNode;
 using cobalt::render_tree::MatrixTransformNode;
+using cobalt::render_tree::Mesh;
 using cobalt::render_tree::MultiPlaneImageDataDescriptor;
 using cobalt::render_tree::Node;
 using cobalt::render_tree::OpacityFilter;
@@ -3291,6 +3297,114 @@
   TestTree(new ImageNode(offscreen_image));
 }
 
+#if defined(ENABLE_MAP_TO_MESH)
+
+namespace {
+scoped_refptr<Mesh> CreateCubeMesh(ResourceProvider* resource_provider) {
+  // Defines a cube mesh where each face faces inward.  Each face has the entire
+  // texture mapped over it.
+  scoped_ptr<std::vector<Mesh::Vertex> > vertices(
+      new std::vector<Mesh::Vertex>);
+
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f));
+
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f));
+
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, 1.0f, 1.0f, 1.0f));
+
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f));
+
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f));
+  vertices->push_back(Mesh::Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f));
+  vertices->push_back(Mesh::Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
+
+  return resource_provider->CreateMesh(
+      vertices.Pass(), Mesh::kDrawModeTriangles);
+}
+
+// Creates a cube mesh with a perspective transform applied to it such that the
+// camera is facing a corner of the cube, from the inside of the cube.
+scoped_refptr<Node> CreateMapToMeshTestRenderTree(
+    ResourceProvider* resource_provider, const scoped_refptr<Image>& texture) {
+  scoped_refptr<Mesh> cube_mesh = CreateCubeMesh(resource_provider);
+  MapToMeshFilter::Builder map_to_mesh_builder;
+  map_to_mesh_builder.SetDefaultMeshes(cube_mesh, cube_mesh);
+  scoped_refptr<FilterNode> map_to_mesh_filter(
+      new FilterNode(MapToMeshFilter(render_tree::kMono, map_to_mesh_builder),
+                     new ImageNode(texture)));
+
+  glm::mat4 model_view =
+      glm::rotate(static_cast<float>(M_PI / 4.0f), glm::vec3(1.0f, 0, 0)) *
+      glm::rotate(static_cast<float>(M_PI / 4.0f), glm::vec3(0, 1.0f, 0));
+
+  const float kNearZ = 0.01f;
+  const float kFarZ = 1000.0f;
+  const float kVerticalFOV = M_PI / 2.0f;
+  const float kAspectRatio = 1.0f;
+  glm::mat4 projection =
+      glm::perspectiveRH(kVerticalFOV, kAspectRatio, kNearZ, kFarZ);
+
+  return new MatrixTransform3DNode(map_to_mesh_filter, projection * model_view);
+}
+}  // namespace
+
+TEST_F(PixelTest, MapToMeshRGBTest) {
+  // Tests that MapToMesh filter works as expected with an RGBA texture.
+  scoped_refptr<Image> image =
+      CreateColoredCheckersImage(GetResourceProvider(), Size(200, 200));
+  TestTree(CreateMapToMeshTestRenderTree(GetResourceProvider(), image));
+}
+
+#if NV12_TEXTURE_SUPPORTED
+
+TEST_F(PixelTest, MapToMeshNV12Test) {
+  // Tests that MapToMesh filter works as expected with a NV12 YUV texture.
+  scoped_refptr<Image> image =
+      MakeNV12Image(GetResourceProvider(), Size(200, 200));
+  TestTree(CreateMapToMeshTestRenderTree(GetResourceProvider(), image));
+}
+
+#endif  // #if NV12_TEXTURE_SUPPORTED
+
+TEST_F(PixelTest, MapToMeshI420Test) {
+  // Tests that MapToMesh filter works as expected with a I420 YUV texture.
+  scoped_refptr<Image> image =
+      MakeI420Image(GetResourceProvider(), Size(200, 200));
+  TestTree(CreateMapToMeshTestRenderTree(GetResourceProvider(), image));
+}
+
+#endif  // defined(ENABLE_MAP_TO_MESH)
+
 }  // namespace rasterizer
 }  // namespace renderer
 }  // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_image.cc b/src/cobalt/renderer/rasterizer/skia/hardware_image.cc
index 432ae5a..5eafdd2 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_image.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_image.cc
@@ -14,6 +14,8 @@
 
 #include "cobalt/renderer/rasterizer/skia/hardware_image.h"
 
+#include <vector>
+
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
 #include "cobalt/renderer/backend/egl/framebuffer_render_target.h"
@@ -350,6 +352,17 @@
   }
 }
 
+HardwareMultiPlaneImage::HardwareMultiPlaneImage(
+    render_tree::MultiPlaneImageFormat format,
+    const std::vector<scoped_refptr<HardwareFrontendImage> >& planes)
+    : size_(planes[0]->GetSize()), format_(format) {
+  DCHECK(planes.size() <=
+         render_tree::MultiPlaneImageDataDescriptor::kMaxPlanes);
+  for (unsigned int i = 0; i < planes.size(); ++i) {
+    planes_[i] = planes[i];
+  }
+}
+
 HardwareMultiPlaneImage::~HardwareMultiPlaneImage() {}
 
 bool HardwareMultiPlaneImage::EnsureInitialized() {
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_image.h b/src/cobalt/renderer/rasterizer/skia/hardware_image.h
index e6d71f2..eb9bb45 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_image.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_image.h
@@ -15,6 +15,8 @@
 #ifndef COBALT_RENDERER_RASTERIZER_SKIA_HARDWARE_IMAGE_H_
 #define COBALT_RENDERER_RASTERIZER_SKIA_HARDWARE_IMAGE_H_
 
+#include <vector>
+
 #include "base/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
@@ -190,6 +192,10 @@
       backend::GraphicsContextEGL* cobalt_context, GrContext* gr_context,
       MessageLoop* rasterizer_message_loop);
 
+  HardwareMultiPlaneImage(
+      render_tree::MultiPlaneImageFormat format,
+      const std::vector<scoped_refptr<HardwareFrontendImage> >& planes);
+
   const math::Size& GetSize() const OVERRIDE { return size_; }
   render_tree::MultiPlaneImageFormat GetFormat() const OVERRIDE {
     return format_;
@@ -204,6 +210,11 @@
     return planes_[plane_index]->GetTextureEGL();
   }
 
+  scoped_refptr<HardwareFrontendImage> GetHardwareFrontendImage(
+      int plane_index) const {
+    return planes_[plane_index];
+  }
+
   bool EnsureInitialized() OVERRIDE;
 
  private:
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index 1fe1492..f88b6ee 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -172,27 +172,28 @@
   // We define a transformation from GLES normalized device coordinates (e.g.
   // [-1.0, 1.0]) into Skia coordinates (e.g. [0, canvas_size.width()]).  This
   // lets us apply Skia's transform inside of Skia's coordinate space.
-  glm::mat3 gl_norm_coords_to_skia_canvas_coords(
-      canvas_size.width() * 0.5f, 0, 0, 0, -canvas_size.height() * 0.5f, 0,
-      canvas_size.width() * 0.5f, canvas_size.height() * 0.5f, 1);
+  glm::mat4 gl_norm_coords_to_skia_canvas_coords(
+      canvas_size.width() * 0.5f, 0, 0, 0, 0, -canvas_size.height() * 0.5f, 0,
+      0, 0, 0, 1, 0, canvas_size.width() * 0.5f, canvas_size.height() * 0.5f, 0,
+      1);
 
   // Convert Skia's current transform from the 3x3 row-major Skia matrix to a
   // 4x4 column-major GLSL matrix.  This is in Skia's coordinate system.
-  glm::mat3 skia_transform_matrix(
-      total_matrix[0], total_matrix[3], total_matrix[6], total_matrix[1],
-      total_matrix[4], total_matrix[7], total_matrix[2],
-      total_matrix[5], total_matrix[8]);
+  glm::mat4 skia_transform_matrix(
+      total_matrix[0], total_matrix[3], 0, total_matrix[6], total_matrix[1],
+      total_matrix[4], 0, total_matrix[7], 0, 0, 1, 0, total_matrix[2],
+      total_matrix[5], 0, total_matrix[8]);
 
   // Finally construct a matrix to map from full screen coordinates into the
   // destination rectangle.  This is in Skia's coordinate system.
-  glm::mat3 dest_rect_matrix(
-      destination_rect.width() / canvas_size.width(), 0, 0, 0,
-      destination_rect.height() / canvas_size.height(), 0,
-      destination_rect.x(), destination_rect.y(), 1);
+  glm::mat4 dest_rect_matrix(
+      destination_rect.width() / canvas_size.width(), 0, 0, 0, 0,
+      destination_rect.height() / canvas_size.height(), 0, 0, 0, 0, 1, 0,
+      destination_rect.x(), destination_rect.y(), 0, 1);
 
   // Since these matrices are applied in LIFO order, read the followin inlined
   // comments in reverse order.
-  return glm::mat4(
+  return
       // Finally transform back into normalized device coordinates so that
       // GL can digest the results.
       glm::affineInverse(gl_norm_coords_to_skia_canvas_coords) *
@@ -204,63 +205,9 @@
       // First transform from normalized device coordinates which the VBO
       // referenced by the RenderQuad() function will have its positions defined
       // within (e.g. [-1, 1]).
-      gl_norm_coords_to_skia_canvas_coords);
+      gl_norm_coords_to_skia_canvas_coords;
 }
 
-}  // namespace
-
-void HardwareRasterizer::Impl::RenderTextureEGL(
-    const render_tree::ImageNode* image_node,
-    RenderTreeNodeVisitorDrawState* draw_state) {
-  HardwareFrontendImage* image =
-      base::polymorphic_downcast<HardwareFrontendImage*>(
-          image_node->data().source.get());
-
-  const backend::TextureEGL* texture = image->GetTextureEGL();
-
-  // Flush the Skia draw state to ensure that all previously issued Skia calls
-  // are rendered so that the following draw command will appear in the correct
-  // order.
-  draw_state->render_target->flush();
-
-  SkISize canvas_size = draw_state->render_target->getBaseLayerSize();
-  GL_CALL(glViewport(0, 0, canvas_size.width(), canvas_size.height()));
-
-  SkIRect canvas_boundsi;
-  draw_state->render_target->getClipDeviceBounds(&canvas_boundsi);
-  GL_CALL(glScissor(canvas_boundsi.x(), canvas_boundsi.y(),
-                    canvas_boundsi.width(), canvas_boundsi.height()));
-
-  if (image->IsOpaque()) {
-    GL_CALL(glDisable(GL_BLEND));
-  } else {
-    GL_CALL(glEnable(GL_BLEND));
-  }
-  GL_CALL(glDisable(GL_DEPTH_TEST));
-  GL_CALL(glDisable(GL_STENCIL_TEST));
-  GL_CALL(glEnable(GL_SCISSOR_TEST));
-
-  if (!textured_mesh_renderer_) {
-    textured_mesh_renderer_.emplace(graphics_context_);
-  }
-  math::Rect content_region(image->GetSize());
-  if (image->GetContentRegion()) {
-    content_region = *image->GetContentRegion();
-  }
-
-  // Invoke our TexturedMeshRenderer to actually perform the draw call.
-  textured_mesh_renderer_->RenderQuad(
-      texture, content_region,
-      GetFallbackTextureModelViewProjectionMatrix(
-          canvas_size, draw_state->render_target->getTotalMatrix(),
-          image_node->data().destination_rect));
-
-  // Let Skia know that we've modified GL state.
-  gr_context_->resetContext();
-}
-
-namespace {
-
 // For stereoscopic video, the actual video is split (either horizontally or
 // vertically) in two, one video for the left eye and one for the right eye.
 // This function will adjust the content region rectangle to match only the
@@ -293,21 +240,141 @@
   return content_region;
 }
 
+egl::TexturedMeshRenderer::Image::Texture GetTextureFromHardwareFrontendImage(
+    HardwareFrontendImage* image, render_tree::StereoMode stereo_mode) {
+  egl::TexturedMeshRenderer::Image::Texture result;
+
+  if (image->GetContentRegion()) {
+    result.content_region = *image->GetContentRegion();
+  } else {
+    // If no content region is explicitly provided, we take this to mean that
+    // the image was created from render_tree::ImageData in which case image
+    // data is defined to be specified top-to-bottom, and so we must flip the
+    // y-axis before passing it on to a GL renderer.
+    math::Size image_size(image->GetSize());
+    result.content_region = math::Rect(
+        0, image_size.height(), image_size.width(), -image_size.height());
+  }
+
+  result.content_region =
+      AdjustContentRegionForStereoMode(stereo_mode, result.content_region);
+  result.texture = image->GetTextureEGL();
+
+  return result;
+}
+
+egl::TexturedMeshRenderer::Image SkiaImageToTexturedMeshRendererImage(
+    Image* image, render_tree::StereoMode stereo_mode) {
+  egl::TexturedMeshRenderer::Image result;
+
+  if (image->GetTypeId() == base::GetTypeId<SinglePlaneImage>()) {
+    HardwareFrontendImage* hardware_image =
+        base::polymorphic_downcast<HardwareFrontendImage*>(image);
+
+    result.type = egl::TexturedMeshRenderer::Image::RGBA;
+    result.textures[0] =
+        GetTextureFromHardwareFrontendImage(hardware_image, stereo_mode);
+  } else if (image->GetTypeId() == base::GetTypeId<MultiPlaneImage>()) {
+    HardwareMultiPlaneImage* hardware_image =
+        base::polymorphic_downcast<HardwareMultiPlaneImage*>(image);
+    if (hardware_image->GetFormat() ==
+        render_tree::kMultiPlaneImageFormatYUV2PlaneBT709) {
+      result.type = egl::TexturedMeshRenderer::Image::YUV_2PLANE_BT709;
+      result.textures[0] = GetTextureFromHardwareFrontendImage(
+          hardware_image->GetHardwareFrontendImage(0), stereo_mode);
+      result.textures[1] = GetTextureFromHardwareFrontendImage(
+          hardware_image->GetHardwareFrontendImage(1), stereo_mode);
+    } else if (hardware_image->GetFormat() ==
+               render_tree::kMultiPlaneImageFormatYUV3PlaneBT709) {
+      result.type = egl::TexturedMeshRenderer::Image::YUV_3PLANE_BT709;
+      result.textures[0] = GetTextureFromHardwareFrontendImage(
+          hardware_image->GetHardwareFrontendImage(0), stereo_mode);
+      result.textures[1] = GetTextureFromHardwareFrontendImage(
+          hardware_image->GetHardwareFrontendImage(1), stereo_mode);
+      result.textures[2] = GetTextureFromHardwareFrontendImage(
+          hardware_image->GetHardwareFrontendImage(2), stereo_mode);
+    }
+  } else {
+    NOTREACHED();
+  }
+
+  return result;
+}
+
+void SetupGLStateForImageRender(Image* image) {
+  if (image->IsOpaque()) {
+    GL_CALL(glDisable(GL_BLEND));
+  } else {
+    GL_CALL(glEnable(GL_BLEND));
+  }
+  GL_CALL(glDisable(GL_DEPTH_TEST));
+  GL_CALL(glDisable(GL_STENCIL_TEST));
+  GL_CALL(glEnable(GL_SCISSOR_TEST));
+  GL_CALL(glEnable(GL_CULL_FACE));
+  GL_CALL(glCullFace(GL_BACK));
+  GL_CALL(glFrontFace(GL_CCW));
+}
+
 }  // namespace
 
+void HardwareRasterizer::Impl::RenderTextureEGL(
+    const render_tree::ImageNode* image_node,
+    RenderTreeNodeVisitorDrawState* draw_state) {
+  Image* image =
+      base::polymorphic_downcast<Image*>(image_node->data().source.get());
+  if (!image) {
+    return;
+  }
+  image->EnsureInitialized();
+
+  // Flush the Skia draw state to ensure that all previously issued Skia calls
+  // are rendered so that the following draw command will appear in the correct
+  // order.
+  draw_state->render_target->flush();
+
+  SkISize canvas_size = draw_state->render_target->getBaseLayerSize();
+  GL_CALL(glViewport(0, 0, canvas_size.width(), canvas_size.height()));
+
+  SkIRect canvas_boundsi;
+  draw_state->render_target->getClipDeviceBounds(&canvas_boundsi);
+  // We need to translate from Skia's top-left corner origin to GL's bottom-left
+  // corner origin.
+  GL_CALL(glScissor(
+      canvas_boundsi.x(),
+      canvas_size.height() - canvas_boundsi.height() - canvas_boundsi.y(),
+      canvas_boundsi.width(), canvas_boundsi.height()));
+
+  SetupGLStateForImageRender(image);
+
+  if (!textured_mesh_renderer_) {
+    textured_mesh_renderer_.emplace(graphics_context_);
+  }
+
+  // Invoke our TexturedMeshRenderer to actually perform the draw call.
+  textured_mesh_renderer_->RenderQuad(
+      SkiaImageToTexturedMeshRendererImage(image, render_tree::kMono),
+      GetFallbackTextureModelViewProjectionMatrix(
+          canvas_size, draw_state->render_target->getTotalMatrix(),
+          image_node->data().destination_rect));
+
+  // Let Skia know that we've modified GL state.
+  uint32_t untouched_states =
+      kMSAAEnable_GrGLBackendState | kStencil_GrGLBackendState |
+      kPixelStore_GrGLBackendState | kFixedFunction_GrGLBackendState |
+      kPathRendering_GrGLBackendState;
+  gr_context_->resetContext(~untouched_states & kAll_GrBackendState);
+}
+
 void HardwareRasterizer::Impl::RenderTextureWithMeshFilterEGL(
     const render_tree::ImageNode* image_node,
     const render_tree::MapToMeshFilter& mesh_filter,
     RenderTreeNodeVisitorDrawState* draw_state) {
-  if (!image_node->data().source) {
+  Image* image =
+      base::polymorphic_downcast<Image*>(image_node->data().source.get());
+  if (!image) {
     return;
   }
-
-  HardwareFrontendImage* image =
-      base::polymorphic_downcast<HardwareFrontendImage*>(
-          image_node->data().source.get());
-
-  const backend::TextureEGL* texture = image->GetTextureEGL();
+  image->EnsureInitialized();
 
   SkISize canvas_size = draw_state->render_target->getBaseLayerSize();
 
@@ -320,39 +387,22 @@
   GL_CALL(glViewport(0, 0, canvas_size.width(), canvas_size.height()));
   GL_CALL(glScissor(0, 0, canvas_size.width(), canvas_size.height()));
 
-  if (image->IsOpaque()) {
-    GL_CALL(glDisable(GL_BLEND));
-  } else {
-    GL_CALL(glEnable(GL_BLEND));
-  }
-  GL_CALL(glDisable(GL_DEPTH_TEST));
-  GL_CALL(glDisable(GL_STENCIL_TEST));
-  GL_CALL(glEnable(GL_SCISSOR_TEST));
-  GL_CALL(glEnable(GL_CULL_FACE));
-  GL_CALL(glCullFace(GL_BACK));
+  SetupGLStateForImageRender(image);
 
   if (!textured_mesh_renderer_) {
     textured_mesh_renderer_.emplace(graphics_context_);
   }
-  math::Rect content_region(image->GetSize());
-  if (image->GetContentRegion()) {
-    content_region = *image->GetContentRegion();
-  }
 
   const VertexBufferObject* mono_vbo =
       base::polymorphic_downcast<HardwareMesh*>(
-          mesh_filter.mono_mesh(math::Size(content_region.width(),
-                                           content_region.height()))
-              .get())
+          mesh_filter.mono_mesh(image->GetSize()).get())
           ->GetVBO();
 
-  math::Rect stereo_adjusted_content_region = AdjustContentRegionForStereoMode(
-      mesh_filter.stereo_mode(), content_region);
-
   // Invoke out TexturedMeshRenderer to actually perform the draw call.
   textured_mesh_renderer_->RenderVBO(
       mono_vbo->GetHandle(), mono_vbo->GetVertexCount(),
-      mono_vbo->GetDrawMode(), texture, stereo_adjusted_content_region,
+      mono_vbo->GetDrawMode(),
+      SkiaImageToTexturedMeshRendererImage(image, mesh_filter.stereo_mode()),
       draw_state->transform_3d);
 
   // Let Skia know that we've modified GL state.
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index e8a4a08..847f2b5 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -149,39 +149,148 @@
 }
 
 #if SB_API_VERSION >= 4 && SB_HAS(GRAPHICS)
+namespace {
+
+#if SB_API_VERSION < SB_DECODE_TARGET_PLANES_FOR_FORMAT
+int PlanesPerFormat(SbDecodeTargetFormat format) {
+  switch (format) {
+    case kSbDecodeTargetFormat1PlaneRGBA:
+      return 1;
+    case kSbDecodeTargetFormat1PlaneBGRA:
+      return 1;
+    case kSbDecodeTargetFormat2PlaneYUVNV12:
+      return 2;
+    case kSbDecodeTargetFormat3PlaneYUVI420:
+      return 3;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+#endif  // SB_API_VERSION < SB_DECODE_TARGET_PLANES_FOR_FORMAT
+
+uint32_t DecodeTargetFormatToGLFormat(SbDecodeTargetFormat format, int plane) {
+  switch (format) {
+    case kSbDecodeTargetFormat1PlaneRGBA: {
+      DCHECK_EQ(0, plane);
+      return GL_RGBA;
+    } break;
+    case kSbDecodeTargetFormat2PlaneYUVNV12: {
+      DCHECK_LT(plane, 2);
+      switch (plane) {
+        case 0:
+          return GL_ALPHA;
+        case 1:
+          return GL_LUMINANCE_ALPHA;
+        default:
+          NOTREACHED();
+          return GL_RGBA;
+      }
+    } break;
+    case kSbDecodeTargetFormat3PlaneYUVI420: {
+      DCHECK_LT(plane, 3);
+      return GL_ALPHA;
+    } break;
+    default: {
+      NOTREACHED();
+      return GL_RGBA;
+    }
+  }
+}
+
+render_tree::MultiPlaneImageFormat
+DecodeTargetFormatToRenderTreeMultiPlaneFormat(SbDecodeTargetFormat format) {
+  switch (format) {
+    case kSbDecodeTargetFormat2PlaneYUVNV12: {
+      return render_tree::kMultiPlaneImageFormatYUV2PlaneBT709;
+    } break;
+    case kSbDecodeTargetFormat3PlaneYUVI420: {
+      return render_tree::kMultiPlaneImageFormatYUV3PlaneBT709;
+    } break;
+    default: { NOTREACHED(); }
+  }
+  return render_tree::kMultiPlaneImageFormatYUV2PlaneBT709;
+}
+
+// Helper class that effectively "ref-count-izes" a SbDecodeTarget so that it
+// can be shared by multiple consumers and only released when we are done with
+// it.
+class DecodeTargetReferenceCounted
+    : public base::RefCountedThreadSafe<DecodeTargetReferenceCounted> {
+ public:
+  explicit DecodeTargetReferenceCounted(SbDecodeTarget decode_target)
+      : decode_target_(decode_target) {}
+
+ private:
+  ~DecodeTargetReferenceCounted() { SbDecodeTargetRelease(decode_target_); }
+
+  SbDecodeTarget decode_target_;
+
+  friend class base::RefCountedThreadSafe<DecodeTargetReferenceCounted>;
+};
+
+void DoNothing(scoped_refptr<DecodeTargetReferenceCounted> decode_target_ref) {
+  // Dummy function that lets us retain a reference to decode_target_ref within
+  // a closure.
+}
+
+}  // namespace
+
 scoped_refptr<render_tree::Image>
     HardwareResourceProvider::CreateImageFromSbDecodeTarget(
         SbDecodeTarget decode_target) {
   SbDecodeTargetInfo info;
   SbMemorySet(&info, 0, sizeof(info));
   CHECK(SbDecodeTargetGetInfo(decode_target, &info));
+  DCHECK_NE(kSbDecodeTargetFormat1PlaneBGRA, info.format);
+
+  std::vector<scoped_refptr<HardwareFrontendImage> > planes;
+  scoped_refptr<DecodeTargetReferenceCounted> decode_target_ref(
+      new DecodeTargetReferenceCounted(decode_target));
 
   // There is limited format support at this time.
-  DCHECK_EQ(info.format, kSbDecodeTargetFormat1PlaneRGBA);
-  const SbDecodeTargetInfoPlane& plane = info.planes[kSbDecodeTargetPlaneRGBA];
+#if SB_API_VERSION >= SB_DECODE_TARGET_PLANES_FOR_FORMAT
+  int planes_per_format = SbDecodeTargetNumberOfPlanesForFormat(info.format);
+#else
+  int planes_per_format = PlanesPerFormat(info.format);
+#endif  // SB_API_VERSION >= SB_DECODE_TARGET_PLANES_FOR_FORMAT
 
-  int gl_handle = plane.texture;
-  render_tree::AlphaFormat alpha_format =
-      info.is_opaque ? render_tree::kAlphaFormatOpaque
-                     : render_tree::kAlphaFormatUnpremultiplied;
+  for (int i = 0; i < planes_per_format; ++i) {
+    const SbDecodeTargetInfoPlane& plane = info.planes[i];
 
-  scoped_ptr<math::Rect> content_region;
-  if (plane.content_region.left != 0 || plane.content_region.top != 0 ||
-      plane.content_region.right != plane.width ||
-      plane.content_region.bottom != plane.height) {
-    content_region.reset(
-        new math::Rect(plane.content_region.left, plane.content_region.top,
-                       plane.content_region.right - plane.content_region.left,
-                       plane.content_region.bottom - plane.content_region.top));
+    int gl_handle = plane.texture;
+    render_tree::AlphaFormat alpha_format =
+        info.is_opaque ? render_tree::kAlphaFormatOpaque
+                       : render_tree::kAlphaFormatUnpremultiplied;
+
+    scoped_ptr<math::Rect> content_region;
+    if (plane.content_region.left != 0 || plane.content_region.top != 0 ||
+        plane.content_region.right != plane.width ||
+        plane.content_region.bottom != plane.height) {
+      content_region.reset(new math::Rect(
+          plane.content_region.left, plane.content_region.top,
+          plane.content_region.right - plane.content_region.left,
+          plane.content_region.bottom - plane.content_region.top));
+    }
+
+    uint32_t gl_format = DecodeTargetFormatToGLFormat(info.format, i);
+
+    scoped_ptr<backend::TextureEGL> texture(new backend::TextureEGL(
+        cobalt_context_, gl_handle, math::Size(plane.width, plane.height),
+        gl_format, plane.gl_texture_target,
+        base::Bind(&DoNothing, decode_target_ref)));
+
+    planes.push_back(make_scoped_refptr(new HardwareFrontendImage(
+        texture.Pass(), alpha_format, cobalt_context_, gr_context_,
+        content_region.Pass(), self_message_loop_)));
   }
 
-  scoped_ptr<backend::TextureEGL> texture(new backend::TextureEGL(
-      cobalt_context_, gl_handle, math::Size(plane.width, plane.height),
-      GL_RGBA, plane.gl_texture_target,
-      base::Bind(&SbDecodeTargetRelease, decode_target)));
-  return make_scoped_refptr(new HardwareFrontendImage(
-      texture.Pass(), alpha_format, cobalt_context_, gr_context_,
-      content_region.Pass(), self_message_loop_));
+  if (info.format == kSbDecodeTargetFormat1PlaneRGBA) {
+    return planes[0];
+  } else {
+    return new HardwareMultiPlaneImage(
+        DecodeTargetFormatToRenderTreeMultiPlaneFormat(info.format), planes);
+  }
 }
 
 namespace {
diff --git a/src/cobalt/renderer/rasterizer/testdata/MapToMeshI420Test-expected.png b/src/cobalt/renderer/rasterizer/testdata/MapToMeshI420Test-expected.png
new file mode 100644
index 0000000..96d70de
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/MapToMeshI420Test-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/MapToMeshNV12Test-expected.png b/src/cobalt/renderer/rasterizer/testdata/MapToMeshNV12Test-expected.png
new file mode 100644
index 0000000..96d70de
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/MapToMeshNV12Test-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/MapToMeshRGBTest-expected.png b/src/cobalt/renderer/rasterizer/testdata/MapToMeshRGBTest-expected.png
new file mode 100644
index 0000000..f7a890b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/MapToMeshRGBTest-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/renderer.gyp b/src/cobalt/renderer/renderer.gyp
index 778b895..3a92967 100644
--- a/src/cobalt/renderer/renderer.gyp
+++ b/src/cobalt/renderer/renderer.gyp
@@ -103,6 +103,11 @@
         '<(DEPTH)/testing/gtest.gyp:gtest',
         'render_tree_pixel_tester',
       ],
+      'conditions': [
+        ['enable_map_to_mesh == 1', {
+          'defines' : ['ENABLE_MAP_TO_MESH'],
+        }],
+      ],
       'actions': [
         {
           'action_name': 'renderer_copy_test_data',
diff --git a/src/cobalt/speech/microphone_fake.cc b/src/cobalt/speech/microphone_fake.cc
index d205ef8..50ec338 100644
--- a/src/cobalt/speech/microphone_fake.cc
+++ b/src/cobalt/speech/microphone_fake.cc
@@ -19,11 +19,11 @@
 #include <algorithm>
 
 #include "base/file_util.h"
+#include "base/logging.h"
 #include "base/path_service.h"
 #include "base/rand_util.h"
 #include "cobalt/audio/audio_file_reader.h"
 #include "starboard/file.h"
-#include "starboard/log.h"
 #include "starboard/memory.h"
 #include "starboard/time.h"
 
@@ -63,18 +63,18 @@
       read_index_(0),
       is_valid_(!ShouldFail(kCreationRange)) {
   if (!is_valid_) {
-    SB_DLOG(WARNING) << "Mocking microphone creation failed.";
+    DLOG(WARNING) << "Mocking microphone creation failed.";
     return;
   }
 
   if (read_data_from_file_) {
     if (options.file_path) {
-      SB_DCHECK(!options.file_path->empty());
+      DCHECK(!options.file_path->empty());
       // External input file.
       file_paths_.push_back(options.file_path.value());
     } else {
       FilePath audio_files_path;
-      SB_CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &audio_files_path));
+      CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &audio_files_path));
       audio_files_path = audio_files_path.Append(FILE_PATH_LITERAL("cobalt"))
                              .Append(FILE_PATH_LITERAL("speech"))
                              .Append(FILE_PATH_LITERAL("testdata"));
@@ -89,31 +89,31 @@
     }
   } else {
     file_length_ = std::min(options.audio_data_size, kMaxBufferSize);
-    SB_DCHECK(file_length_ > 0);
+    DCHECK(file_length_ > 0);
     file_buffer_.reset(new uint8[file_length_]);
     SbMemoryCopy(file_buffer_.get(), options.external_audio_data, file_length_);
   }
 }
 
 bool MicrophoneFake::Open() {
-  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (ShouldFail(kOpenRange)) {
-    SB_DLOG(WARNING) << "Mocking microphone open failed.";
+    DLOG(WARNING) << "Mocking microphone open failed.";
     return false;
   }
 
   if (read_data_from_file_) {
     // Read from local files.
-    SB_DCHECK(file_paths_.size() != 0);
+    DCHECK(file_paths_.size() != 0);
     size_t random_index =
         static_cast<size_t>(base::RandGenerator(file_paths_.size()));
     starboard::ScopedFile file(file_paths_[random_index].value().c_str(),
                                kSbFileOpenOnly | kSbFileRead, NULL, NULL);
-    SB_DCHECK(file.IsValid());
+    DCHECK(file.IsValid());
     int file_buffer_size =
         std::min(static_cast<int>(file.GetSize()), kMaxBufferSize);
-    SB_DCHECK(file_buffer_size > 0);
+    DCHECK(file_buffer_size > 0);
 
     scoped_array<char> audio_input(new char[file_buffer_size]);
     int read_bytes = file.ReadAll(audio_input.get(), file_buffer_size);
@@ -151,10 +151,10 @@
 }
 
 int MicrophoneFake::Read(char* out_data, int data_size) {
-  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (ShouldFail(kReadRange)) {
-    SB_DLOG(WARNING) << "Mocking microphone read failed.";
+    DLOG(WARNING) << "Mocking microphone read failed.";
     return -1;
   }
 
@@ -169,7 +169,7 @@
 }
 
 bool MicrophoneFake::Close() {
-  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (read_data_from_file_) {
     file_buffer_.reset();
@@ -179,7 +179,7 @@
   read_index_ = 0;
 
   if (ShouldFail(kCloseRange)) {
-    SB_DLOG(WARNING) << "Mocking microphone close failed.";
+    DLOG(WARNING) << "Mocking microphone close failed.";
     return false;
   }
 
diff --git a/src/cobalt/streams/embedded_scripts/readable_stream.js b/src/cobalt/streams/embedded_scripts/readable_stream.js
index 3017cdd..6a27d8c 100644
--- a/src/cobalt/streams/embedded_scripts/readable_stream.js
+++ b/src/cobalt/streams/embedded_scripts/readable_stream.js
@@ -44,4 +44,5 @@
 cancelResult)}return promise}}function DequeueValue(controller){const result=controller[_queue].shift();controller[_totalQueuedSize]-=result.size;return result.value}function EnqueueValueWithSize(controller,value,size){size=Number(size);if(Number_isNaN(size)||size===+Infinity||size<0)throw new RangeError(streamErrors_invalidSize);controller[_totalQueuedSize]+=size;controller[_queue].push({value,size})}function GetTotalQueueSize(controller){return controller[_totalQueuedSize]}function ValidateAndNormalizeQueuingStrategy(size,
 highWaterMark){if(size!==undefined&&typeof size!=="function")throw new TypeError(streamErrors_sizeNotAFunction);highWaterMark=Number(highWaterMark);if(Number_isNaN(highWaterMark))throw new RangeError(streamErrors_invalidHWM);if(highWaterMark<0)throw new RangeError(streamErrors_invalidHWM);return{size,highWaterMark}}function CallOrNoop(O,P,arg,nameForError){const method=O[P];if(method===undefined)return undefined;if(typeof method!=="function")throw new TypeError(errTmplMustBeFunctionOrUndefined(nameForError));
 return callFunction(method,O,arg)}function PromiseCallOrNoop(O,P,arg,nameForError){let method;try{method=O[P]}catch(methodE){return Promise_reject(methodE)}if(method===undefined)return Promise_resolve(undefined);if(typeof method!=="function")return Promise_reject(new TypeError(errTmplMustBeFunctionOrUndefined(nameForError)));try{return Promise_resolve(callFunction(method,O,arg))}catch(e){return Promise_reject(e)}}function CreateIterResultObject(value,done){return{value,done}}defineProperty(global,
-"ReadableStream",{value:ReadableStream,enumerable:false,configurable:true,writable:true})})(this);
\ No newline at end of file
+"ReadableStream",{value:ReadableStream,enumerable:false,configurable:true,writable:true});global.AcquireReadableStreamDefaultReader=AcquireReadableStreamDefaultReader;global.IsReadableStream=IsReadableStream;global.IsReadableStreamDisturbed=IsReadableStreamDisturbed;global.IsReadableStreamLocked=IsReadableStreamLocked;global.IsReadableStreamReadable=IsReadableStreamReadable;global.IsReadableStreamClosed=IsReadableStreamClosed;global.IsReadableStreamErrored=IsReadableStreamErrored;global.IsReadableStreamDefaultReader=
+IsReadableStreamDefaultReader;global.ReadableStreamDefaultReaderRead=ReadableStreamDefaultReaderRead;global.ReadableStreamTee=ReadableStreamTee;global.ReadableStreamDefaultControllerClose=ReadableStreamDefaultControllerClose;global.ReadableStreamDefaultControllerGetDesiredSize=ReadableStreamDefaultControllerGetDesiredSize;global.ReadableStreamDefaultControllerEnqueue=ReadableStreamDefaultControllerEnqueue;global.ReadableStreamDefaultControllerError=ReadableStreamDefaultControllerError})(this);
\ No newline at end of file
diff --git a/src/cobalt/streams/readable_stream.js b/src/cobalt/streams/readable_stream.js
index 5943f89..edeb9cd 100644
--- a/src/cobalt/streams/readable_stream.js
+++ b/src/cobalt/streams/readable_stream.js
@@ -1057,23 +1057,23 @@
   // Exports to Blink
   //
 
+  global.AcquireReadableStreamDefaultReader = AcquireReadableStreamDefaultReader;
+  global.IsReadableStream = IsReadableStream;
+  global.IsReadableStreamDisturbed = IsReadableStreamDisturbed;
+  global.IsReadableStreamLocked = IsReadableStreamLocked;
+  global.IsReadableStreamReadable = IsReadableStreamReadable;
+  global.IsReadableStreamClosed = IsReadableStreamClosed;
+  global.IsReadableStreamErrored = IsReadableStreamErrored;
+  global.IsReadableStreamDefaultReader = IsReadableStreamDefaultReader;
+  global.ReadableStreamDefaultReaderRead = ReadableStreamDefaultReaderRead;
+  global.ReadableStreamTee = ReadableStreamTee;
+
+  global.ReadableStreamDefaultControllerClose = ReadableStreamDefaultControllerClose;
+  global.ReadableStreamDefaultControllerGetDesiredSize = ReadableStreamDefaultControllerGetDesiredSize;
+  global.ReadableStreamDefaultControllerEnqueue = ReadableStreamDefaultControllerEnqueue;
+  global.ReadableStreamDefaultControllerError = ReadableStreamDefaultControllerError;
+
 /*
-  binding.AcquireReadableStreamDefaultReader = AcquireReadableStreamDefaultReader;
-  binding.IsReadableStream = IsReadableStream;
-  binding.IsReadableStreamDisturbed = IsReadableStreamDisturbed;
-  binding.IsReadableStreamLocked = IsReadableStreamLocked;
-  binding.IsReadableStreamReadable = IsReadableStreamReadable;
-  binding.IsReadableStreamClosed = IsReadableStreamClosed;
-  binding.IsReadableStreamErrored = IsReadableStreamErrored;
-  binding.IsReadableStreamDefaultReader = IsReadableStreamDefaultReader;
-  binding.ReadableStreamDefaultReaderRead = ReadableStreamDefaultReaderRead;
-  binding.ReadableStreamTee = ReadableStreamTee;
-
-  binding.ReadableStreamDefaultControllerClose = ReadableStreamDefaultControllerClose;
-  binding.ReadableStreamDefaultControllerGetDesiredSize = ReadableStreamDefaultControllerGetDesiredSize;
-  binding.ReadableStreamDefaultControllerEnqueue = ReadableStreamDefaultControllerEnqueue;
-  binding.ReadableStreamDefaultControllerError = ReadableStreamDefaultControllerError;
-
   binding.createReadableStreamWithExternalController =
       (underlyingSource, strategy) => {
         return new ReadableStream(
diff --git a/src/cobalt/version.h b/src/cobalt/version.h
index 8cd1366..09c5600 100644
--- a/src/cobalt/version.h
+++ b/src/cobalt/version.h
@@ -15,6 +15,6 @@
 #define COBALT_VERSION_H_
 
 // Cobalt release number.
-#define COBALT_VERSION "10"
+#define COBALT_VERSION "11"
 
 #endif  // COBALT_VERSION_H_
diff --git a/src/cobalt/webdriver_benchmarks/container_util.py b/src/cobalt/webdriver_benchmarks/container_util.py
index cab9451..56e948a 100644
--- a/src/cobalt/webdriver_benchmarks/container_util.py
+++ b/src/cobalt/webdriver_benchmarks/container_util.py
@@ -50,38 +50,5 @@
   if len(sorted_values) == index + 1:
     return sorted_values[index]
 
-  return sorted_values[index] * (1 - fractional
-                                ) + sorted_values[index + 1] * fractional
-
-
-def merge_dict(merge_into, merge_from):
-  """Merges the second dict into the first dict.
-
-  Merge into differs from update in that it will not override values.  If the
-  values already exist, the resulting value will be a list with a union of
-  existing and new items.
-
-  Args:
-    merge_into: An output dict to merge values into.
-    merge_from: An input dict to iterate over and insert values from.
-
-  Returns:
-    None
-  """
-  if not merge_from:
-    return
-  for k, v in merge_from.items():
-    try:
-      existing_value = merge_into[k]
-    except KeyError:
-      merge_into[k] = v
-      continue
-
-    if not isinstance(v, list):
-      v = [v]
-    if isinstance(existing_value, list):
-      existing_value.extend(v)
-    else:
-      new_value = [existing_value]
-      new_value.extend(v)
-      merge_into[k] = new_value
+  return sorted_values[index] * (
+      1 - fractional) + sorted_values[index + 1] * fractional
diff --git a/src/cobalt/webdriver_benchmarks/container_util_test.py b/src/cobalt/webdriver_benchmarks/container_util_test.py
index 371a61f..8c29bb4 100755
--- a/src/cobalt/webdriver_benchmarks/container_util_test.py
+++ b/src/cobalt/webdriver_benchmarks/container_util_test.py
@@ -85,50 +85,5 @@
     self.assertEqual(container_util.percentile([2, 1, 3, 4, 5], 100), 5)
 
 
-class MergeDictTest(unittest.TestCase):
-
-  def test_empty_merge(self):
-    a = {'x': 4}
-    b = {}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': 4})
-
-  def test_merge_into_empty(self):
-    a = {}
-    b = {'x': 4}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': 4})
-
-  def test_merge_non_overlapping_item(self):
-    a = {'x': 4}
-    b = {'y': 5}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': 4, 'y': 5})
-
-  def test_overlapping_item_with_item(self):
-    a = {'x': 4}
-    b = {'x': 5}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': [4, 5]})
-
-  def test_overlapping_list_with_item(self):
-    a = {'x': [4]}
-    b = {'x': 5}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': [4, 5]})
-
-  def test_overlapping_list_with_list(self):
-    a = {'x': [4]}
-    b = {'x': [5]}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': [4, 5]})
-
-  def test_overlapping_item_with_list(self):
-    a = {'x': 4}
-    b = {'x': [5]}
-    container_util.merge_dict(a, b)
-    self.assertEqual(a, {'x': [4, 5]})
-
-
 if __name__ == '__main__':
   sys.exit(unittest.main())
diff --git a/src/cobalt/webdriver_benchmarks/tests/README.md b/src/cobalt/webdriver_benchmarks/tests/README.md
index ca89b03..bd9f865 100644
--- a/src/cobalt/webdriver_benchmarks/tests/README.md
+++ b/src/cobalt/webdriver_benchmarks/tests/README.md
@@ -5,18 +5,19 @@
 
 Each file should contain a set of tests in Python "unittest" format.
 
-All tests in all of the files included within [all.py](all.py) will be run on
-the build system. Results can be recorded in the build results database.
+All tests included within [performance.py](performance.py) will be run on the
+build system. Results can be recorded in the build results database.
 
 ## Running the tests
 
-In most cases, you will want to run all tests, and you can do so by executing
-the script [all.py](all.py).  You can call `python all.py --help` to see a list
-of commandline parameters to call it with.  For example, to run tests on the
-raspi-2 QA build, you should run the following command:
+In most cases, you will want to run all performance tests, and you can do so by
+executing the script [performance.py](performance.py). You can call
+`python performance.py --help` to see a list of commandline parameters to call
+it with.  For example, to run tests on the raspi-2 QA build, you should run the
+following command:
 
 ```
-python all.py -p raspi-2 -c qa -d $RASPI_ADDR
+python performance.py -p raspi-2 -c qa -d $RASPI_ADDR
 ```
 
 Where `RASPI_ADDR` is set to the IP of the target Raspberry Pi device.
@@ -29,10 +30,11 @@
 
  1. If appropriate, create a new file borrowing the boilerplate from
     an existing simple file, such as
-    [browse_horizontal.py](browse_horizontal.py).
+    [browse_horizontal.py](performance/non_video/browse_horizontal.py).
 
- 2. Add the file name to the tests added within [all.py](all.py), causing it run
-    when [all.py](all.py) is run.
+ 2. Add the file name to the tests added within
+    [performance.py](performance.py), causing it run when
+    [performance](performance.py) is run.
 
  3. If this file contains internal names or details, consider adding it
     to the "EXCLUDE.FILES" list.
@@ -44,37 +46,15 @@
     the internal
     [README-Updating-Result-Schema.md](README-Updating-Result-Schema.md) file.
 
-## Testing arbitrary loaders
+## Testing against specific loaders/labels
 
-Unfortunately we haven't yet had the time to implement an easy way to adjust
-the test URL query parameters.  In order to adjust the query parameters to test,
-you should do the following:
+To run the benchmarks against any desired loader, a --url command line parameter
+can be provided. This will be the url that the tests will run against.
 
-Open [../tv_testcase_util.py](../tv_testcase_util.py) and in the function
-`get_url()`, replace the line
+It should have the following format:
 
 ```
-query_dict = BASE_PARAMS.copy()
-```
-
-with
-
-```
-query_dict = {}
-```
-
-and then append the following else-clause to the `if query_params:` statement,
-
-```
-else:
-  query_dict = BASE_PARAMS.copy()
-```
-
-and then finally, near the top of the file, modify `BASE_PARAMS` to include all
-query parameters you would like to test.  For example,
-
-```
-BASE_PARAMS = {"loader": "airc"}
+python performance.py -p raspi-2 -c qa -d $RASPI_ADDR --url https://www.youtube.com/tv?loader=nllive
 ```
 
 ## Benchmark Results
@@ -157,7 +137,7 @@
 interested in.  You can do so with `grep`, for example:
 
 ```
-python all.py -p raspi-2 -c qa -d $RASPI_ADDR > results.txt
+python performance.py -p raspi-2 -c qa -d $RASPI_ADDR > results.txt
 echo "" > filtered_results.txt
 grep -o "wbStartupDurBlankToBrowseUs.*$" results.txt >> filtered_results.txt
 grep -o "wbBrowseToWatchDurVideoStartDelay.*$" results.txt >> filtered_results.txt
diff --git a/src/cobalt/webdriver_benchmarks/tests/all.py b/src/cobalt/webdriver_benchmarks/tests/performance.py
old mode 100755
new mode 100644
similarity index 64%
copy from src/cobalt/webdriver_benchmarks/tests/all.py
copy to src/cobalt/webdriver_benchmarks/tests/performance.py
index c08d93c..8495f71
--- a/src/cobalt/webdriver_benchmarks/tests/all.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance.py
@@ -1,5 +1,5 @@
 #!/usr/bin/python2
-"""Target for running all tests cases."""
+"""Target for running all performance test cases."""
 
 from __future__ import absolute_import
 from __future__ import division
@@ -30,15 +30,8 @@
   test_suite = unittest.TestSuite()
   dir_path = os.path.dirname(__file__)
 
-  # "time_to_shelf" must be the first test added. The timings that it
-  # records require it to run first.
-  _add_test(test_suite, dir_path, "startup")
-  _add_test(test_suite, dir_path, "browse_horizontal")
-  _add_test(test_suite, dir_path, "browse_vertical")
-  _add_test(test_suite, dir_path, "browse_to_guide")
-  _add_test(test_suite, dir_path, "browse_to_search")
-  _add_test(test_suite, dir_path, "browse_to_watch")
-  _add_test(test_suite, dir_path, "csi")
+  _add_test(test_suite, dir_path, "performance_non_video")
+  _add_test(test_suite, dir_path, "performance_video")
 
   return test_suite
 
diff --git a/src/cobalt/webdriver_benchmarks/tests/performance/__init__.py b/src/cobalt/webdriver_benchmarks/tests/performance/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/__init__.py
diff --git a/src/cobalt/webdriver_benchmarks/tests/performance/non_video/__init__.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/__init__.py
diff --git a/src/cobalt/webdriver_benchmarks/tests/browse_horizontal.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_horizontal.py
similarity index 86%
rename from src/cobalt/webdriver_benchmarks/tests/browse_horizontal.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_horizontal.py
index dd21b3e..2da83c6 100755
--- a/src/cobalt/webdriver_benchmarks/tests/browse_horizontal.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_horizontal.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import tv_testcase
diff --git a/src/cobalt/webdriver_benchmarks/tests/browse_to_guide.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_guide.py
similarity index 89%
rename from src/cobalt/webdriver_benchmarks/tests/browse_to_guide.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_guide.py
index 4a74c4a..7e5230f 100755
--- a/src/cobalt/webdriver_benchmarks/tests/browse_to_guide.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_guide.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import tv
diff --git a/src/cobalt/webdriver_benchmarks/tests/browse_to_search.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_search.py
similarity index 90%
rename from src/cobalt/webdriver_benchmarks/tests/browse_to_search.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_search.py
index 688e939..b04e8ab 100755
--- a/src/cobalt/webdriver_benchmarks/tests/browse_to_search.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_to_search.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import tv
diff --git a/src/cobalt/webdriver_benchmarks/tests/browse_vertical.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_vertical.py
similarity index 85%
rename from src/cobalt/webdriver_benchmarks/tests/browse_vertical.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_vertical.py
index fb31b69..08a687e 100755
--- a/src/cobalt/webdriver_benchmarks/tests/browse_vertical.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/browse_vertical.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import tv_testcase
diff --git a/src/cobalt/webdriver_benchmarks/tests/startup.py b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/startup.py
similarity index 90%
rename from src/cobalt/webdriver_benchmarks/tests/startup.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/non_video/startup.py
index 4ea17fd..997a0fc 100755
--- a/src/cobalt/webdriver_benchmarks/tests/startup.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/non_video/startup.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import timer
diff --git a/src/cobalt/webdriver_benchmarks/tests/performance/video/__init__.py b/src/cobalt/webdriver_benchmarks/tests/performance/video/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/video/__init__.py
diff --git a/src/cobalt/webdriver_benchmarks/tests/browse_to_watch.py b/src/cobalt/webdriver_benchmarks/tests/performance/video/browse_to_watch.py
similarity index 91%
rename from src/cobalt/webdriver_benchmarks/tests/browse_to_watch.py
rename to src/cobalt/webdriver_benchmarks/tests/performance/video/browse_to_watch.py
index ed2f73e..0c958fb 100755
--- a/src/cobalt/webdriver_benchmarks/tests/browse_to_watch.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance/video/browse_to_watch.py
@@ -8,8 +8,11 @@
 import os
 import sys
 
-# The parent directory is a module
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+# Add the base webdriver_benchmarks path
+sys.path.insert(0,
+                os.path.dirname(
+                    os.path.dirname((os.path.dirname(
+                        os.path.dirname(os.path.realpath(__file__)))))))
 
 # pylint: disable=C6204,C6203
 import tv_testcase
diff --git a/src/cobalt/webdriver_benchmarks/tests/all.py b/src/cobalt/webdriver_benchmarks/tests/performance_non_video.py
old mode 100755
new mode 100644
similarity index 78%
rename from src/cobalt/webdriver_benchmarks/tests/all.py
rename to src/cobalt/webdriver_benchmarks/tests/performance_non_video.py
index c08d93c..d385177
--- a/src/cobalt/webdriver_benchmarks/tests/all.py
+++ b/src/cobalt/webdriver_benchmarks/tests/performance_non_video.py
@@ -1,5 +1,5 @@
 #!/usr/bin/python2
-"""Target for running all tests cases."""
+"""Target for running non-video performance test cases."""
 
 from __future__ import absolute_import
 from __future__ import division
@@ -18,10 +18,11 @@
 
 
 def _add_test(test_suite, dir_path, test_name):
-  if os.path.isfile(os.path.join(dir_path, test_name + ".py")):
+  if os.path.isfile(
+      os.path.join(dir_path, "performance", "non_video", test_name + ".py")):
     print("Adding test: {}".format(test_name))
     test_suite.addTest(unittest.TestLoader().loadTestsFromModule(
-        importlib.import_module("tests." + test_name)))
+        importlib.import_module("tests.performance.non_video." + test_name)))
 
 
 # pylint: disable=unused-argument
@@ -30,14 +31,13 @@
   test_suite = unittest.TestSuite()
   dir_path = os.path.dirname(__file__)
 
-  # "time_to_shelf" must be the first test added. The timings that it
+  # "startup" must be the first test added. The timings that it
   # records require it to run first.
   _add_test(test_suite, dir_path, "startup")
   _add_test(test_suite, dir_path, "browse_horizontal")
   _add_test(test_suite, dir_path, "browse_vertical")
   _add_test(test_suite, dir_path, "browse_to_guide")
   _add_test(test_suite, dir_path, "browse_to_search")
-  _add_test(test_suite, dir_path, "browse_to_watch")
   _add_test(test_suite, dir_path, "csi")
 
   return test_suite
diff --git a/src/cobalt/webdriver_benchmarks/tests/performance_video.py b/src/cobalt/webdriver_benchmarks/tests/performance_video.py
new file mode 100755
index 0000000..3784cc2
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/performance_video.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python2
+"""Target for running video performance test cases."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import importlib
+import os
+import sys
+import unittest
+
+# The parent directory is a module
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+
+# pylint: disable=C6204,C6203
+import tv_testcase
+
+
+def _add_test(test_suite, dir_path, test_name):
+  if os.path.isfile(
+      os.path.join(dir_path, "performance", "video", test_name + ".py")):
+    print("Adding test: {}".format(test_name))
+    test_suite.addTest(unittest.TestLoader().loadTestsFromModule(
+        importlib.import_module("tests.performance.video." + test_name)))
+
+
+# pylint: disable=unused-argument
+def load_tests(loader, tests, pattern):
+  """This is a Python unittest "load_tests protocol method."""
+  test_suite = unittest.TestSuite()
+  dir_path = os.path.dirname(__file__)
+
+  _add_test(test_suite, dir_path, "browse_to_watch")
+
+  return test_suite
+
+
+if __name__ == "__main__":
+  tv_testcase.main()
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase.py b/src/cobalt/webdriver_benchmarks/tv_testcase.py
index dfdb5d9..9840228 100644
--- a/src/cobalt/webdriver_benchmarks/tv_testcase.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase.py
@@ -72,12 +72,15 @@
       # include experiments. Additionally, loading this URL triggers a reload.
       query_params = {"env_forcedOffAllExperiments": True}
       triggers_reload = True
-      self.load_tv(None, query_params, triggers_reload)
+      self.load_tv(query_params, triggers_reload)
       _is_initialized = True
 
   def get_webdriver(self):
     return tv_testcase_runner.GetWebDriver()
 
+  def get_default_url(self):
+    return tv_testcase_runner.GetDefaultUrl()
+
   def get_cval(self, cval_name):
     """Returns the Python object represented by a JSON cval string.
 
@@ -103,26 +106,18 @@
     self.get_webdriver().get("about:blank")
     self.wait_for_url_loaded_events()
 
-  def load_tv(self,
-              label=None,
-              additional_query_params=None,
-              triggers_reload=False):
+  def load_tv(self, query_params=None, triggers_reload=False):
     """Loads the main TV page and waits for it to display.
 
     Args:
-      label: A value for the label query parameter.
-      additional_query_params: A dict containing additional query parameters.
+      query_params: A dict containing additional query parameters.
       triggers_reload: Whether or not the navigation will trigger a reload.
     Raises:
       Underlying WebDriver exceptions
     """
-    query_params = {}
-    if label is not None:
-      query_params = {"label": label}
-    if additional_query_params is not None:
-      query_params.update(additional_query_params)
     self.clear_url_loaded_events()
-    self.get_webdriver().get(tv_testcase_util.get_tv_url(query_params))
+    self.get_webdriver().get(
+        tv_testcase_util.generate_url(self.get_default_url(), query_params))
     self.wait_for_url_loaded_events()
     if triggers_reload:
       self.clear_url_loaded_events()
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase_runner.py b/src/cobalt/webdriver_benchmarks/tv_testcase_runner.py
index 829c337..53ccbd4 100755
--- a/src/cobalt/webdriver_benchmarks/tv_testcase_runner.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase_runner.py
@@ -27,7 +27,7 @@
 arg_parser.add_argument(
     "-e",
     "--executable",
-    help="Path to cobalt executable. "
+    help="Path to Cobalt executable. "
     "Auto-derived if absent.")
 arg_parser.add_argument(
     "-c",
@@ -42,6 +42,12 @@
     help="Devkit or IP address for app_launcher."
     "Current hostname used if absent.")
 arg_parser.add_argument(
+    "--command_line",
+    nargs="*",
+    help="Command line arguments to pass to the Cobalt executable.")
+arg_parser.add_argument(
+    "--url", help="Specifies the URL to run the tests against.")
+arg_parser.add_argument(
     "-o", "--log_file", help="Logfile pathname. stdout if absent.")
 
 # Pattern to match Cobalt log line for when the WebDriver port has been
@@ -67,6 +73,7 @@
 _webdriver = None
 _windowdriver_created = threading.Event()
 _webmodule_loaded = threading.Event()
+_default_url = "https://www.youtube.com/tv"
 
 
 def GetWebDriver():
@@ -84,6 +91,11 @@
   return _webmodule_loaded
 
 
+def GetDefaultUrl():
+  """Returns the default url to use with tests."""
+  return _default_url
+
+
 class TimeoutException(Exception):
   pass
 
@@ -99,7 +111,9 @@
   failed = False
   should_exit = threading.Event()
 
-  def __init__(self, platform, executable, devkit_name, log_file_path):
+  def __init__(self, platform, executable, devkit_name, command_line_args,
+               default_url, log_file_path):
+    global _default_url
     self.selenium_webdriver_module = tv_testcase_util.import_selenium_module(
         "webdriver")
 
@@ -113,11 +127,17 @@
         platform, executable, devkit_name=devkit_name, close_output_file=False)
 
     args = []
+    if command_line_args is not None:
+      for command_line_arg in command_line_args:
+        args.append("--" + command_line_arg)
     args.append("--enable_webdriver")
     args.append("--null_savegame")
     args.append("--debug_console=off")
     args.append("--url=about:blank")
 
+    if default_url is not None:
+      _default_url = default_url
+
     self.launcher.SetArgs(args)
     self.launcher.SetOutputCallback(self._HandleLine)
     self.log_file_path = log_file_path
@@ -138,8 +158,8 @@
   def __exit__(self, exc_type, exc_value, traceback):
     # The unittest module terminates with a SystemExit
     # If this is a successful exit, then this is a successful run
-    success = exc_type is None or (exc_type is SystemExit and not exc_value.code
-                                  )
+    success = exc_type is None or (exc_type is SystemExit and
+                                   not exc_value.code)
     self.SetShouldExit(failed=not success)
     self.thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
 
@@ -263,8 +283,8 @@
     executable = GetCobaltExecutablePath(platform, args.config)
 
   try:
-    with CobaltRunner(platform, executable, args.devkit_name,
-                      args.log_file) as runner:
+    with CobaltRunner(platform, executable, args.devkit_name, args.command_line,
+                      args.url, args.log_file) as runner:
       unittest.main(testRunner=unittest.TextTestRunner(
           verbosity=0, stream=runner.log_file))
   except TimeoutException:
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase_util.py b/src/cobalt/webdriver_benchmarks/tv_testcase_util.py
index 34d574a..eb1154d 100644
--- a/src/cobalt/webdriver_benchmarks/tv_testcase_util.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase_util.py
@@ -22,11 +22,6 @@
 EVENT_TYPE_KEY_DOWN = "KeyDown"
 EVENT_TYPE_KEY_UP = "KeyUp"
 
-# URL-related constants
-BASE_URL = "https://www.youtube.com/"
-TV_APP_PATH = "/tv"
-BASE_PARAMS = {}
-
 
 def import_selenium_module(submodule=None):
   """Dynamically imports a selenium.webdriver submodule.
@@ -61,23 +56,16 @@
   return module
 
 
-def get_url(path, query_params=None):
+def generate_url(default_url, query_params):
   """Returns the URL indicated by the path and query parameters."""
-  parsed_url = list(urlparse.urlparse(BASE_URL))
-  parsed_url[2] = path
-  query_dict = BASE_PARAMS.copy()
-  if query_params:
-    query_dict.update(urlparse.parse_qsl(parsed_url[4]))
-    container_util.merge_dict(query_dict, query_params)
-  parsed_url[4] = urlencode(query_dict, doseq=True)
+  if not query_params:
+    return default_url
+
+  parsed_url = list(urlparse.urlparse(default_url))
+  parsed_url[4] = urlencode(query_params, doseq=True)
   return urlparse.urlunparse(parsed_url)
 
 
-def get_tv_url(query_params=None):
-  """Returns the tv URL indicated by the query parameters."""
-  return get_url(TV_APP_PATH, query_params)
-
-
 def record_test_result(name, result):
   """Records an individual scalar result of a benchmark test.
 
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc
index cd119d6..3a9c8e3 100644
--- a/src/cobalt/xhr/xml_http_request.cc
+++ b/src/cobalt/xhr/xml_http_request.cc
@@ -380,6 +380,15 @@
   last_progress_time_ = base::TimeTicks();
 }
 
+void XMLHttpRequest::Fetch(
+    const FetchUpdateCallbackArg& fetch_callback,
+    const base::optional<RequestBodyType>& request_body,
+    script::ExceptionState* exception_state) {
+  fetch_callback_.reset(
+      new FetchUpdateCallbackArg::Reference(this, fetch_callback));
+  Send(request_body, exception_state);
+}
+
 base::optional<std::string> XMLHttpRequest::GetResponseHeader(
     const std::string& header) {
   // https://www.w3.org/TR/2014/WD-XMLHttpRequest-20140130/#the-getresponseheader()-method
@@ -599,15 +608,18 @@
                                       mime_type_override_);
   }
 
+  // Reserve space for the content in the case of a regular XHR request.
   DCHECK_EQ(response_body_.size(), 0);
-  const int64 content_length = http_response_headers_->GetContentLength();
+  if (!fetch_callback_) {
+    const int64 content_length = http_response_headers_->GetContentLength();
 
-  // If we know the eventual content length, allocate the total response body.
-  // Otherwise just reserve a reasonably large initial chunk.
-  size_t bytes_to_reserve = content_length > 0
-                                ? static_cast<size_t>(content_length)
-                                : kInitialReceivingBufferSize;
-  response_body_.Reserve(bytes_to_reserve);
+    // If we know the eventual content length, allocate the total response body.
+    // Otherwise just reserve a reasonably large initial chunk.
+    size_t bytes_to_reserve = content_length > 0
+                                  ? static_cast<size_t>(content_length)
+                                  : kInitialReceivingBufferSize;
+    response_body_.Reserve(bytes_to_reserve);
+  }
 
   ChangeState(kHeadersReceived);
 
@@ -620,10 +632,25 @@
   UNREFERENCED_PARAMETER(source);
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_NE(state_, kDone);
-  response_body_.Append(reinterpret_cast<const uint8*>(download_data->data()),
-                        download_data->size());
+
+  // Preserve the response body only for regular XHR requests. Fetch requests
+  // process the response in pieces, so do not need to keep the whole response.
+  if (!fetch_callback_) {
+    response_body_.Append(reinterpret_cast<const uint8*>(download_data->data()),
+                          download_data->size());
+  }
+
   ChangeState(kLoading);
 
+  if (fetch_callback_) {
+    scoped_refptr<dom::Uint8Array> data = new dom::Uint8Array(
+          settings_,
+          reinterpret_cast<const uint8*>(download_data->data()),
+          static_cast<uint32>(download_data->size()),
+          NULL);
+    fetch_callback_->value().Run(data);
+  }
+
   // Send a progress notification if at least 50ms have elapsed.
   const base::TimeTicks now = base::TimeTicks::Now();
   const base::TimeDelta elapsed(now - last_progress_time_);
@@ -635,6 +662,7 @@
 
 void XMLHttpRequest::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  fetch_callback_.reset();
   const net::URLRequestStatus& status = source->GetStatus();
   if (status.is_success()) {
     stop_timeout_ = true;
@@ -741,6 +769,8 @@
   FireProgressEvent(this, base::Tokens::progress());
   FireProgressEvent(this, error_name);
   FireProgressEvent(this, base::Tokens::loadend());
+
+  fetch_callback_.reset();
   AllowGarbageCollection();
 }
 
diff --git a/src/cobalt/xhr/xml_http_request.h b/src/cobalt/xhr/xml_http_request.h
index 7a7f997..6646e05 100644
--- a/src/cobalt/xhr/xml_http_request.h
+++ b/src/cobalt/xhr/xml_http_request.h
@@ -27,6 +27,7 @@
 #include "cobalt/dom/csp_delegate.h"
 #include "cobalt/dom/document.h"
 #include "cobalt/dom/dom_exception.h"
+#include "cobalt/dom/uint8_array.h"
 #include "cobalt/loader/net_fetcher.h"
 #include "cobalt/script/union_type.h"
 #include "cobalt/xhr/xhr_response_data.h"
@@ -127,6 +128,14 @@
   void Send(const base::optional<RequestBodyType>& request_body,
             script::ExceptionState* exception_state);
 
+  // FetchAPI: replacement for Send() when fetch functionality is required.
+  typedef script::CallbackFunction<
+      void(const scoped_refptr<dom::Uint8Array>& data)> FetchUpdateCallback;
+  typedef script::ScriptValue<FetchUpdateCallback> FetchUpdateCallbackArg;
+  void Fetch(const FetchUpdateCallbackArg& fetch_callback,
+             const base::optional<RequestBodyType>& request_body,
+             script::ExceptionState* exception_state);
+
   base::optional<std::string> GetResponseHeader(const std::string& header);
   std::string GetAllResponseHeaders();
 
@@ -247,6 +256,9 @@
   base::TimeTicks last_progress_time_;
   base::TimeTicks upload_last_progress_time_;
 
+  // FetchAPI: transfer progress callback.
+  scoped_ptr<FetchUpdateCallbackArg::Reference> fetch_callback_;
+
   // All members requiring initialization are grouped below.
   dom::DOMSettings* settings_;
   State state_;
diff --git a/src/cobalt/xhr/xml_http_request.idl b/src/cobalt/xhr/xml_http_request.idl
index a95bfcd..d8d7bdc 100644
--- a/src/cobalt/xhr/xml_http_request.idl
+++ b/src/cobalt/xhr/xml_http_request.idl
@@ -45,6 +45,11 @@
         optional (DOMString or ArrayBufferView or ArrayBuffer)? request_body);
     void abort();
 
+    // FetchAPI: replacement for "send" when fetch functionality is needed.
+    [RaisesException] void fetch(
+        FetchUpdateCallback fetch_callback,
+        (DOMString or ArrayBufferView or ArrayBuffer)? request_body);
+
     // response
     readonly attribute unsigned short status;
     readonly attribute DOMString statusText;
@@ -65,3 +70,6 @@
 // as a nullable EventListener for now until we can do some refactoring to
 // accept both in the EventTarget implementation.
 typedef EventListener? EventHandler;
+
+// FetchAPI: custom callback to allow progressive updates.
+callback FetchUpdateCallback = void(Uint8Array data);
diff --git a/src/media/base/starboard_player.cc b/src/media/base/starboard_player.cc
index 07799db..55d813b 100644
--- a/src/media/base/starboard_player.cc
+++ b/src/media/base/starboard_player.cc
@@ -366,6 +366,16 @@
   audio_header.average_bytes_per_second = 1;
   audio_header.block_alignment = 4;
   audio_header.bits_per_sample = audio_config_.bits_per_channel();
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  audio_header.audio_specific_config_size =
+      static_cast<uint16_t>(audio_config_.extra_data_size());
+  if (audio_header.audio_specific_config_size == 0) {
+    audio_header.audio_specific_config = NULL;
+  } else {
+    audio_header.audio_specific_config =
+        static_cast<int16_t*>(&audio_config_.extra_data()[0]);
+  }
+#else   // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
   audio_header.audio_specific_config_size = static_cast<uint16_t>(
       std::min(audio_config_.extra_data_size(),
                sizeof(audio_header.audio_specific_config)));
@@ -373,6 +383,7 @@
     SbMemoryCopy(audio_header.audio_specific_config, audio_config_.extra_data(),
                  audio_header.audio_specific_config_size);
   }
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
 
   SbMediaAudioCodec audio_codec =
       MediaAudioCodecToSbMediaAudioCodec(audio_config_.codec());
diff --git a/src/media/player/buffered_data_source.h b/src/media/player/buffered_data_source.h
index ca09aad..9c6a31c 100644
--- a/src/media/player/buffered_data_source.h
+++ b/src/media/player/buffered_data_source.h
@@ -35,6 +35,12 @@
 // TODO: Investigate if we still need BufferedDataSource.
 class BufferedDataSource : public DataSource {
  public:
+  typedef base::Callback<void(bool)> DownloadingStatusCB;
+
+  virtual void SetDownloadingStatusCB(
+      const DownloadingStatusCB& downloading_status_cb) {
+    UNREFERENCED_PARAMETER(downloading_status_cb);
+  }
   virtual void SetPreload(Preload preload) { UNREFERENCED_PARAMETER(preload); }
   virtual bool HasSingleOrigin() { return true; }
   virtual bool DidPassCORSAccessCheck() const { return true; }
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc
index f22efba..e94219d 100644
--- a/src/media/player/web_media_player_impl.cc
+++ b/src/media/player/web_media_player_impl.cc
@@ -306,6 +306,8 @@
   scoped_refptr<base::MessageLoopProxy> message_loop =
       message_loop_factory_->GetMessageLoop(MessageLoopFactory::kPipeline);
 
+  data_source->SetDownloadingStatusCB(
+      base::Bind(&WebMediaPlayerImpl::OnDownloadingStatusChanged, AsWeakPtr()));
   proxy_->set_data_source(data_source.Pass());
 
   is_local_source_ = !url.SchemeIs("http") && !url.SchemeIs("https");
@@ -1073,7 +1075,7 @@
   GetClient()->SetOpaque(opaque);
 }
 
-void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
+void WebMediaPlayerImpl::OnDownloadingStatusChanged(bool is_downloading) {
   if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
     SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
   else if (is_downloading &&
diff --git a/src/media/player/web_media_player_impl.h b/src/media/player/web_media_player_impl.h
index d211776..2400412 100644
--- a/src/media/player/web_media_player_impl.h
+++ b/src/media/player/web_media_player_impl.h
@@ -241,7 +241,7 @@
 
  private:
   // Called when the data source is downloading or paused.
-  void NotifyDownloading(bool is_downloading);
+  void OnDownloadingStatusChanged(bool is_downloading);
 
   // Finishes starting the pipeline due to a call to load().
   void StartPipeline();
diff --git a/src/nb/analytics/memory_tracker_impl_test.cc b/src/nb/analytics/memory_tracker_impl_test.cc
index 11f4f01..c5be817 100644
--- a/src/nb/analytics/memory_tracker_impl_test.cc
+++ b/src/nb/analytics/memory_tracker_impl_test.cc
@@ -509,7 +509,7 @@
       EXPECT_EQ_NO_TRACKING(0, num_allocations);
       EXPECT_EQ_NO_TRACKING(0, allocation_bytes);
 
-      num_allocations = allocation_bytes = -1;
+      allocation_bytes = num_allocations = -1;
       group_b->GetAggregateStats(&num_allocations, &allocation_bytes);
       EXPECT_EQ_NO_TRACKING(2, num_allocations);
       EXPECT_EQ_NO_TRACKING(8, allocation_bytes);
diff --git a/src/nb/lexical_cast_test.cc b/src/nb/lexical_cast_test.cc
index 88b56d5..1108024 100644
--- a/src/nb/lexical_cast_test.cc
+++ b/src/nb/lexical_cast_test.cc
@@ -55,9 +55,9 @@
   EXPECT_FLOAT_EQ(1234.5f, lexical_cast<float>("1234.5f", &cast_ok));

   EXPECT_TRUE(cast_ok);

 

-  EXPECT_FLOAT_EQ(1234.5f, lexical_cast<double>("1234.5", &cast_ok));

+  EXPECT_DOUBLE_EQ(1234.5, lexical_cast<double>("1234.5", &cast_ok));

   EXPECT_TRUE(cast_ok);

-  EXPECT_FLOAT_EQ(1234.5f, lexical_cast<double>("1234.5f", &cast_ok));

+  EXPECT_DOUBLE_EQ(1234.5, lexical_cast<double>("1234.5f", &cast_ok));

   EXPECT_TRUE(cast_ok);

 }

 

@@ -88,9 +88,9 @@
   EXPECT_FLOAT_EQ(-1234.5f, lexical_cast<float>("-1234.5f", &cast_ok));

   EXPECT_TRUE(cast_ok);

 

-  EXPECT_FLOAT_EQ(-1234.5f, lexical_cast<double>("-1234.5", &cast_ok));

+  EXPECT_DOUBLE_EQ(-1234.5f, lexical_cast<double>("-1234.5", &cast_ok));

   EXPECT_TRUE(cast_ok);

-  EXPECT_FLOAT_EQ(-1234.5f, lexical_cast<double>("-1234.5f", &cast_ok));

+  EXPECT_DOUBLE_EQ(-1234.5f, lexical_cast<double>("-1234.5f", &cast_ok));

   EXPECT_TRUE(cast_ok);

 }

 

@@ -109,7 +109,7 @@
 

   EXPECT_FLOAT_EQ(0.f, lexical_cast<float>("not a number", &cast_ok));

   EXPECT_FALSE(cast_ok);

-  EXPECT_FLOAT_EQ(0.0, lexical_cast<double>("not a number", &cast_ok));

+  EXPECT_DOUBLE_EQ(0.0, lexical_cast<double>("not a number", &cast_ok));

   EXPECT_FALSE(cast_ok);

 }

 

diff --git a/src/nb/string_interner.cc b/src/nb/string_interner.cc
index b4da03a..562a2d4 100644
--- a/src/nb/string_interner.cc
+++ b/src/nb/string_interner.cc
@@ -118,7 +118,7 @@
 
 nb::StringInterner&
 ConcurrentStringInterner::GetBucket(const char* string, size_t n) {
-  uint32_t hash_value = nb::RuntimeHash32(string, n);
+  uint32_t hash_value = nb::RuntimeHash32(string, static_cast<int>(n));
   size_t index =
     static_cast<size_t>(hash_value % string_interner_table_.size());
   return *string_interner_table_[index];
@@ -126,7 +126,7 @@
 
 const nb::StringInterner&
 ConcurrentStringInterner::GetBucket(const char* string, size_t n) const {
-  uint32_t hash_value = nb::RuntimeHash32(string, n);
+  uint32_t hash_value = nb::RuntimeHash32(string, static_cast<int>(n));
   size_t index =
     static_cast<size_t>(hash_value % string_interner_table_.size());
   return *string_interner_table_[index];
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index d9629f6..1446709 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -6,6 +6,26 @@
 this file describes the changes made to the Starboard interface since the
 version previous to it.
 
+## Version 5
+
+### Add Speech Recognizer API
+Introduce `starboard/speech_recognizer.h`.
+This newly-introduced `starboard/speech_recognizer.h` adds the on-device speech
+recognizer feature.
+
+### Added new system property to allow platform-specific user agent suffixes
+Adds `kSbSystemPropertyUserAgentAuxField` to the `SbSystemPropertyId` enum to
+allow platform-specific User-Agent suffix.
+
+### Remove unused enums from `starboard/input.h`
+The following unused enum values are removed from `starboard/input.h`:
+  * `kSbInputDeviceTypeMicrophone`
+  * `kSbInputDeviceTypeSpeechCommand`
+  * `kSbInputEventTypeAudio`
+  * `kSbInputEventTypeCommand`
+  * `kSbInputEventTypeGrab`
+  * `kSbInputEventTypeUngrab`
+
 ## Version 4
 
 ### Decode-to-Texture Player Output Mode
diff --git a/src/starboard/README.md b/src/starboard/README.md
index 5e81034..16a8cda 100644
--- a/src/starboard/README.md
+++ b/src/starboard/README.md
@@ -173,7 +173,7 @@
 
   1. Recursively copy `src/starboard/stub` to
      `src/third_party/starboard/<family-name>/<binary-variant>`.  You may also
-     consider copying from another reference platform, like `raspi-1` or
+     consider copying from another reference platform, like `raspi-2` or
      `linux-x64x11`.
   1. In `gyp_configuration.py`
       1. In the `CreatePlatformConfig()` function, pass your
diff --git a/src/starboard/common/common.cc b/src/starboard/common/common.cc
index 1200a32..e1e90c1 100644
--- a/src/starboard/common/common.cc
+++ b/src/starboard/common/common.cc
@@ -14,10 +14,17 @@
 
 #include "starboard/configuration.h"
 
-// This audit is here so it is only displayed once every build.
+// These audits are here so they are only displayed once every build.
+
 #if SB_API_VERSION == SB_EXPERIMENTAL_API_VERSION
 #pragma message( \
-    "Your platform's SB_API_VERSION == SB_EXPERIMENTAL_API_VERSION.")
+    "Your platform's SB_API_VERSION == SB_EXPERIMENTAL_API_VERSION. " \
+    "You are implementing the Experimental version of Starboard at your " \
+    "own risk!  We don't recommend this for third parties.")
+#endif
+
+#if SB_API_VERSION == SB_RELEASE_CANDIDATE_API_VERSION
 #pragma message( \
-    "You are implementing the experimental SB API at your own risk!")
+    "Your platform's SB_API_VERSION == SB_RELEASE_CANDIDATE_API_VERSION. " \
+    "Note that the RC version of Starboard is still subject to change.")
 #endif
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index 742cded..dcfe06f 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -39,12 +39,19 @@
 
 // The maximum API version allowed by this version of the Starboard headers,
 // inclusive.
-#define SB_MAXIMUM_API_VERSION 5
+#define SB_MAXIMUM_API_VERSION 6
 
 // The API version that is currently open for changes, and therefore is not
 // stable or frozen. Production-oriented ports should avoid declaring that they
 // implement the experimental Starboard API version.
-#define SB_EXPERIMENTAL_API_VERSION 5
+#define SB_EXPERIMENTAL_API_VERSION 6
+
+// The next API version to be frozen, but is still subject to emergency
+// changes. It is reasonable to base a port on the Release Candidate API
+// version, but be aware that small incompatible changes may still be made to
+// it.
+// #undef SB_RELEASE_CANDIDATE_API_VERSION
+#define SB_RELEASE_CANDIDATE_API_VERSION 5
 
 // --- Experimental Feature Defines ------------------------------------------
 
@@ -56,22 +63,32 @@
 //   // Introduce new experimental feature.
 //   //   Add a function, `SbMyNewFeature()` to `starboard/feature.h` which
 //   //   exposes functionality for my new feature.
-//   #define SB_MY_EXPERIMENTAL_FEATURE VERSION SB_EXPERIMENTAL_API_VERSION
-
-// Adds kSbSystemPropertyUserAgentAuxField to the SbSystemPropertyId
-// enum to allow platform-specific  User-Agent suffix.
-// NOLINTNEXTLINE(whitespace/line_length)
-#define SB_USER_AGENT_AUX_SYSTEM_PROPERTY_API_VERSION SB_EXPERIMENTAL_API_VERSION
-
-// Introduce 'starboard/speech_recognizer.h'
-// This newly-introduced 'starboard/speech_recognizer.h' adds the on-device
-// speech recognizer feature.
-#define SB_SPEECH_RECOGNIZER_API_VERSION SB_EXPERIMENTAL_API_VERSION
+//   #define SB_MY_EXPERIMENTAL_FEATURE_VERSION SB_EXPERIMENTAL_API_VERSION
 
 // Introduce pointer (mouse) input support. This extends the SbInput interface
 // with some enum values and data members to allow mouse, wheel, and more
 // generic pointer input.
 #define SB_POINTER_INPUT_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// SbMediaAudioHeader::audio_specific_config will be a pointer instead of an
+// array.
+#define SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER SB_EXPERIMENTAL_API_VERSION
+
+// Removes SbTimeZoneGetDstName() - Daylight saving time version of time zone.
+// Changes SbTimeZoneGetName() is more flexible now in what it is allowed to
+// return.
+#define SB_TIME_ZONE_FLEXIBLE_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// Adds the convenience inline function, SbDecodeTargetNumberOfPlanesForFormat()
+// to starboard/decode_target.h.
+#define SB_DECODE_TARGET_PLANES_FOR_FORMAT SB_EXPERIMENTAL_API_VERSION
+
+// --- Release Candidate Feature Defines -------------------------------------
+
+#define SB_USER_AGENT_AUX_SYSTEM_PROPERTY_API_VERSION \
+  SB_RELEASE_CANDIDATE_API_VERSION
+#define SB_SPEECH_RECOGNIZER_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
+
 // --- Common Detected Features ----------------------------------------------
 
 #if defined(__GNUC__)
@@ -561,7 +578,7 @@
 #if !defined(SB_HAS_SPEECH_RECOGNIZER)
 #error "Your platform must define SB_HAS_SPEECH_RECOGNIZER."
 #endif  // !defined(SB_HAS_SPEECH_RECOGNIZER)
-#endif  // SB_API_VERSION >= SB_EXPERIMENTAL_API_VERSION
+#endif  // SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
 
 // --- Derived Configuration -------------------------------------------------
 
diff --git a/src/starboard/decode_target.h b/src/starboard/decode_target.h
index 20e1f70..afe2e46 100644
--- a/src/starboard/decode_target.h
+++ b/src/starboard/decode_target.h
@@ -93,6 +93,7 @@
 
 #include "starboard/configuration.h"
 #include "starboard/export.h"
+#include "starboard/log.h"
 #include "starboard/types.h"
 
 #if SB_API_VERSION >= 3
@@ -338,6 +339,25 @@
   return format != kSbDecodeTargetFormatInvalid;
 }
 
+#if SB_API_VERSION >= SB_DECODE_TARGET_PLANES_FOR_FORMAT
+static SB_C_INLINE int SbDecodeTargetNumberOfPlanesForFormat(
+    SbDecodeTargetFormat format) {
+  switch (format) {
+    case kSbDecodeTargetFormat1PlaneRGBA:
+      return 1;
+    case kSbDecodeTargetFormat1PlaneBGRA:
+      return 1;
+    case kSbDecodeTargetFormat2PlaneYUVNV12:
+      return 2;
+    case kSbDecodeTargetFormat3PlaneYUVI420:
+      return 3;
+    default:
+      SB_NOTREACHED();
+      return 0;
+  }
+}
+#endif  // SB_API_VERSION >= SB_DECODE_TARGET_PLANES_FOR_FORMAT
+
 #if SB_API_VERSION < 4
 
 #if SB_HAS(BLITTER)
diff --git a/src/starboard/doc/versioning.md b/src/starboard/doc/versioning.md
index 9f714cb..6931625 100644
--- a/src/starboard/doc/versioning.md
+++ b/src/starboard/doc/versioning.md
@@ -1,6 +1,7 @@
 # Starboard Versioning
 
 ## Motivation
+
 When a porter implements Starboard for a platform, it is more precise to say
 that they have implemented support for a certain version of Starboard.
 Changes to the Starboard API are associated with Starboard versions. Any usage
@@ -11,6 +12,7 @@
 have implemented is still supported.
 
 ## Starboard API version vs. Starboard application version
+
 The Starboard version describes the set of Starboard APIs available to Starboard
 applications. It will be incremented with every open-source release that
 includes changes to the Starboard API. Reasons to increment the Starboard API
@@ -43,6 +45,7 @@
 would be unavailable.
 
 ## Range of supported Starboard versions
+
 The minimum supported API version is defined by the `SB_MINIMUM_API_VERSION`
 macro, which is defined in starboard/configuration.h. Likewise, the
 `SB_MAXIMUM_API_VERSION` macro defines the maximum supported API version. All
@@ -57,6 +60,7 @@
 require porters to implement a newer version of Starboard.
 
 ## Using new Starboard APIs from Starboard Applications
+
 Usage of a Starboard API that is not available in all supported Starboard API
 versions must be guarded with a check for `SB_API_VERSION`. Starboard
 applications must continue to function correctly and must not disable existing
@@ -64,30 +68,65 @@
 new functionality in Starboard applications if this evaluates to false.
 
 ## Adding and using new Starboard APIs
-### “experimental” Starboard version
+
+### The "Experimental" Starboard Version
+
 At any given time, exactly one version of Starboard will be denoted as the
-“experimental” version, as defined by the `SB_EXPERIMENTAL_API_VERSION` macro in
-starboard/configuration.h. It is generally not recommended to declare support
+"experimental" version, as defined by the `SB_EXPERIMENTAL_API_VERSION` macro in
+`starboard/configuration.h`. It is generally not recommended to declare support
 for this version. Any Starboard APIs defined in the experimental version are
 subject to change and API requirements could be added, removed, or changed at
 any time.
-### “frozen” Starboard versions
-All Starboard versions that are less than the experimental version are
-considered frozen. Any Starboard APIs in a frozen version shall not change as
-long as that version is supported by Cobalt.
+
+### The "Release Candidate" Starboard Version
+
+At any given time, zero or one versions of Starboard will be denoted as the
+"release candidate" version, as defined by the
+`SB_RELEASE_CANDIDATE_API_VERSION` macro in `starboard/configuration.h`. The
+"release candidate" version is a set of API changes that have been considered
+and tested together. It is reasonable to port against this version, it has gone
+through some stabilization and may become frozen as it currently is. But, be
+aware that it is possible that minor incompatible changes may be made to this
+version if an unexpected situation arises. `SB_RELEASE_CANDIDATE_API_VERSION` is
+not defined if there is no "release candidate" version.
+
+### "Frozen" Starboard versions
+
+All Starboard versions that are less than the experimental and release candidate
+versions are considered frozen. Any Starboard APIs in a frozen version MUST not
+change.
+
+### Version Numbers, and how They Interrelate Numerically
+
+```
+frozen < release-candidate < experimental < future
+```
+
+As mentioned previously, a release candidate version may or may not exist at any
+given time.  When there is a release candate version, it follows the invariant
+above.
+
 ### Life of a Starboard API
+
 New Starboard APIs should be defined in the experimental version.
 
 When introducing a new Starboard API (or modifying an existing one), a new
 feature version define should be created within the "Experimental Feature
-Defines" section of starboard/configuration.h, and set to
+Defines" section of `starboard/configuration.h`, and set to
 `SB_EXPERIMENTAL_API_VERSION`. A well written comment should be added in front
 of the feature define that describes exactly what is introduced by the feature.
 In the comment, all new/modified/removed symbols should be identified, and all
 modified header files should be named.
+
 For example,
 
 ```
+// in starboard/configuration.h
+
+#define SB_EXPERIMENTAL_API_VERSION 7
+
+#undef SB_RELEASE_CANDIDATE_API_VERSION
+
 // --- Experimental Feature Defines ------------------------------------------
 
 ...
@@ -103,6 +142,10 @@
 // Introduce a new API in starboard/new_functionality.h which declares the
 // function SbNewFunctionality().
 #define SB_MY_NEW_FEATURE_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// Introduce another new API in starboard/still_in_development.h which
+// declares the function SbStillInDevelopment().
+#define SB_MY_OTHER_NEW_FEATURE_API_VERSION SB_EXPERIMENTAL_API_VERSION
 ```
 
 When declaring the new interface, the following syntax should be used:
@@ -125,12 +168,43 @@
 #endif
 ```
 
-When a new version of a Starboard Application that requires new Starboard APIs
-is to be released, these new Starboard APIs will be frozen to the value of the
-current experimental version, and the experimental version will be incremented
-by one.  Additionally, the feature define should be removed, and its comment
-moved into the (newly created) section for the corresponding version in
-starboard/CHANGELOG.md.
+When promoting the experimental API version to be the release candidate API
+version, the previously undefined `SB_RELEASE_CANDIDATE_API_VERSION` is set to
+the current value of `SB_EXPERIMENTAL_API_VERSION`, and
+`SB_EXPERIMENTAL_API_VERSION` is then incremented by one. As a result,
+`SB_RELEASE_CANDIDATE_API_VERSION` on the master branch should always either be
+undefined, or `SB_EXPERIMENTAL_API_VERSION - 1`.
+
+One or more features are then moved from `SB_EXPERIMENTAL_API_VERSION` to
+`SB_RELEASE_CANDIDATE_API_VERSION`, and into the "Release Candidate Feature
+Defines" section of `starboard/configuration.h`. Some features may be left in
+experimental if they are not ready for release. The documentation comments of
+these features should be moved into the (newly created) section for the
+corresponding version in [starboard/CHANGELOG.md](../CHANGELOG.md).
+
+```
+// in starboard/configuration.h
+
+#define SB_EXPERIMENTAL_API_VERSION 8
+
+#define SB_RELEASE_CANDIDATE_API_VERSION 7
+
+// --- Experimental Feature Defines ------------------------------------------
+
+// Introduce another new API in starboard/still_in_development.h which
+// declares the function SbStillInDevelopment().
+#define SB_MY_OTHER_NEW_FEATURE_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// --- Release Candidate Features Defines ------------------------------------
+
+#define SB_MY_NEW_FEATURE_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
+
+```
+
+When a release candidate branch is promoted to a full release, these new
+Starboard APIs will be irrevocably frozen to the value of
+`SB_RELEASE_CANDIDATE_API_VERSION`, and the release candidate version will be
+undefined. Additionally, the feature defines should be removed.
 
 ```
 // starboard/new_functionality.h
@@ -145,6 +219,7 @@
 
 // starboard/configuration.h
 #define SB_EXPERIMENTAL_API_VERSION 8
+#undef SB_RELEASE_CANDIDATE_API_VERSION
 
 // cobalt/new_feature.cc
 #if SB_API_VERSION >= 7
@@ -154,11 +229,12 @@
 #endif
 ```
 
-A developer who increments the experimental version must ensure that stubs and
-reference platforms declare support for the new experimental version through
-their respective `SB_API_VERSION` macros.
+Whoever increments the experimental version must ensure that stubs and reference
+platforms declare support for the new experimental version through their
+respective `SB_API_VERSION` macros.
 
 ### Communicating Starboard API changes to porters
+
 When a new version of Starboard is released, [starboard/CHANGELOG.md](../CHANGELOG.md) should be
 updated with the feature define comments for all features enabled in that
 version.
diff --git a/src/starboard/input.h b/src/starboard/input.h
index c6e0fd7..0b2eba4 100644
--- a/src/starboard/input.h
+++ b/src/starboard/input.h
@@ -49,7 +49,7 @@
   // Produces |Press| and |Unpress| events.
   kSbInputDeviceTypeKeyboard,
 
-#if SB_API_VERSION <= 4
+#if SB_API_VERSION < 5
   // Input from a microphone that would provide audio data to the caller, who
   // may then find some way to detect speech or other sounds within it. It may
   // have processed or filtered the audio in some way before it arrives.
@@ -68,7 +68,7 @@
   // Produces |Press| and |Unpress| events.
   kSbInputDeviceTypeRemote,
 
-#if SB_API_VERSION <= 4
+#if SB_API_VERSION < 5
   // Input from a speech command analyzer, which is some hardware or software
   // that, given a set of known phrases, activates when one of the registered
   // phrases is heard.
@@ -90,7 +90,7 @@
 
 // The action that an input event represents.
 typedef enum SbInputEventType {
-#if SB_API_VERSION <= 4
+#if SB_API_VERSION < 5
   // Receipt of Audio. Some audio data was received by the input microphone.
   kSbInputEventTypeAudio,
   // Receipt of a command. A command was received from some semantic source,
@@ -112,7 +112,7 @@
   // Injecting repeat presses is up to the client.
   kSbInputEventTypePress,
 
-#if SB_API_VERSION <= 4
+#if SB_API_VERSION < 5
   // Grab deactivation. This event type is deprecated.
   kSbInputEventTypeUngrab,
 #endif
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/linux/x64x11/mock/atomic_public.h
similarity index 68%
copy from src/starboard/raspi/1/atomic_public.h
copy to src/starboard/linux/x64x11/mock/atomic_public.h
index 6fa6273..c03b468 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/linux/x64x11/mock/atomic_public.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#ifndef STARBOARD_LINUX_X64X11_MOCK_ATOMIC_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_MOCK_ATOMIC_PUBLIC_H_
 
-#include "starboard/raspi/shared/atomic_public.h"
+#include "starboard/linux/shared/atomic_public.h"
 
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#endif  // STARBOARD_LINUX_X64X11_MOCK_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/mock/configuration_public.h b/src/starboard/linux/x64x11/mock/configuration_public.h
new file mode 100644
index 0000000..0fdbea7
--- /dev/null
+++ b/src/starboard/linux/x64x11/mock/configuration_public.h
@@ -0,0 +1,478 @@
+// Copyright 2017 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.
+
+// The Starboard configuration for a mock implementation designed to be
+// built on Desktop Linux.
+
+#ifndef STARBOARD_LINUX_X64X11_MOCK_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_MOCK_CONFIGURATION_PUBLIC_H_
+
+// The API version implemented by this platform. This will generally be set to
+// the current value of SB_MAXIMUM_API_VERSION at the time of implementation.
+#define SB_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// --- Architecture Configuration --------------------------------------------
+
+// Whether the current platform is big endian. SB_IS_LITTLE_ENDIAN will be
+// automatically set based on this.
+#define SB_IS_BIG_ENDIAN 0
+
+// Whether the current platform is an ARM architecture.
+#define SB_IS_ARCH_ARM 0
+
+// Whether the current platform is a MIPS architecture.
+#define SB_IS_ARCH_MIPS 0
+
+// Whether the current platform is a PPC architecture.
+#define SB_IS_ARCH_PPC 0
+
+// Whether the current platform is an x86 architecture.
+#define SB_IS_ARCH_X86 1
+
+// Assume a 64-bit architecture.
+#define SB_IS_32_BIT 0
+#define SB_IS_64_BIT 1
+
+// Whether the current platform's pointers are 32-bit.
+// Whether the current platform's longs are 32-bit.
+#if SB_IS(32_BIT)
+#define SB_HAS_32_BIT_POINTERS 1
+#define SB_HAS_32_BIT_LONG 1
+#else
+#define SB_HAS_32_BIT_POINTERS 0
+#define SB_HAS_32_BIT_LONG 0
+#endif
+
+// Whether the current platform's pointers are 64-bit.
+// Whether the current platform's longs are 64-bit.
+#if SB_IS(64_BIT)
+#define SB_HAS_64_BIT_POINTERS 1
+#define SB_HAS_64_BIT_LONG 1
+#else
+#define SB_HAS_64_BIT_POINTERS 0
+#define SB_HAS_64_BIT_LONG 0
+#endif
+
+// Configuration parameters that allow the application to make some general
+// compile-time decisions with respect to the the number of cores likely to be
+// available on this platform. For a definitive measure, the application should
+// still call SbSystemGetNumberOfProcessors at runtime.
+
+// Whether the current platform is expected to have many cores (> 6), or a
+// wildly varying number of cores.
+#define SB_HAS_MANY_CORES 1
+
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
+// Whether the current platform is expected to have exactly 2 cores.
+#define SB_HAS_2_CORES 0
+
+// Whether the current platform is expected to have exactly 4 cores.
+#define SB_HAS_4_CORES 0
+
+// Whether the current platform is expected to have exactly 6 cores.
+#define SB_HAS_6_CORES 0
+
+// Whether the current platform supports thread priorities.
+#define SB_HAS_THREAD_PRIORITY_SUPPORT 0
+
+// Whether the current platform's thread scheduler will automatically balance
+// threads between cores, as opposed to systems where threads will only ever run
+// on the specifically pinned core.
+#define SB_HAS_CROSS_CORE_SCHEDULER 1
+
+// Some platforms will not align variables on the stack with an alignment
+// greater than 16 bytes. Platforms where this is the case should define the
+// following quirk.
+#undef SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES
+
+// --- System Header Configuration -------------------------------------------
+
+// Any system headers listed here that are not provided by the platform will be
+// emulated in starboard/types.h.
+
+// Whether the current platform provides the standard header stdarg.h.
+#define SB_HAS_STDARG_H 1
+
+// Whether the current platform provides the standard header stdbool.h.
+#define SB_HAS_STDBOOL_H 1
+
+// Whether the current platform provides the standard header stddef.h.
+#define SB_HAS_STDDEF_H 1
+
+// Whether the current platform provides the standard header stdint.h.
+#define SB_HAS_STDINT_H 1
+
+// Whether the current platform provides the standard header inttypes.h.
+#define SB_HAS_INTTYPES_H 1
+
+// Whether the current platform provides the standard header wchar.h.
+#define SB_HAS_WCHAR_H 1
+
+// Whether the current platform provides the standard header limits.h.
+#define SB_HAS_LIMITS_H 1
+
+// Whether the current platform provides the standard header float.h.
+#define SB_HAS_FLOAT_H 1
+
+// Whether the current platform provides ssize_t.
+#define SB_HAS_SSIZE_T 1
+
+// Whether the current platform has microphone supported.
+#define SB_HAS_MICROPHONE 1
+
+// Whether the current platform has speech recognizer.
+#define SB_HAS_SPEECH_RECOGNIZER 1
+
+// Whether the current platform has speech synthesis.
+#define SB_HAS_SPEECH_SYNTHESIS 1
+
+// Type detection for wchar_t.
+#if defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define SB_IS_WCHAR_T_UTF32 1
+#elif defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+#define SB_IS_WCHAR_T_UTF16 1
+#endif
+
+// Chrome only defines these two if ARMEL or MIPSEL are defined.
+#if defined(__ARMEL__)
+// Chrome has an exclusion for iOS here, we should too when we support iOS.
+#define SB_IS_WCHAR_T_UNSIGNED 1
+#elif defined(__MIPSEL__)
+#define SB_IS_WCHAR_T_SIGNED 1
+#endif
+
+// --- Compiler Configuration ------------------------------------------------
+
+// The platform's annotation for forcing a C function to be inlined.
+#define SB_C_FORCE_INLINE __inline__ __attribute__((always_inline))
+
+// The platform's annotation for marking a C function as suggested to be
+// inlined.
+#define SB_C_INLINE inline
+
+// The platform's annotation for marking a C function as forcibly not
+// inlined.
+#define SB_C_NOINLINE __attribute__((noinline))
+
+// The platform's annotation for marking a symbol as exported outside of the
+// current shared library.
+#define SB_EXPORT_PLATFORM __attribute__((visibility("default")))
+
+// The platform's annotation for marking a symbol as imported from outside of
+// the current linking unit.
+#define SB_IMPORT_PLATFORM
+
+// On some platforms the __GNUC__ is defined even though parts of the
+// functionality are missing. Setting this to non-zero allows disabling missing
+// functionality encountered.
+#undef SB_HAS_QUIRK_COMPILER_SAYS_GNUC_BUT_ISNT
+
+// On some compilers, the frontend has a quirk such that #ifdef cannot
+// correctly detect __has_feature is defined, and an example error you get is:
+#undef SB_HAS_QUIRK_HASFEATURE_NOT_DEFINED_BUT_IT_IS
+
+// --- Extensions Configuration ----------------------------------------------
+
+// GCC/Clang doesn't define a long long hash function, except for Android and
+// Game consoles.
+#define SB_HAS_LONG_LONG_HASH 0
+
+// GCC/Clang doesn't define a string hash function, except for Game Consoles.
+#define SB_HAS_STRING_HASH 0
+
+// Desktop Linux needs a using statement for the hash functions.
+#define SB_HAS_HASH_USING 0
+
+// Set this to 1 if hash functions for custom types can be defined as a
+// hash_value() function. Otherwise, they need to be placed inside a
+// partially-specified hash struct template with an operator().
+#define SB_HAS_HASH_VALUE 0
+
+// Set this to 1 if use of hash_map or hash_set causes a deprecation warning
+// (which then breaks the build).
+#define SB_HAS_HASH_WARNING 1
+
+// The location to include hash_map on this platform.
+#define SB_HASH_MAP_INCLUDE <ext/hash_map>
+
+// C++'s hash_map and hash_set are often found in different namespaces depending
+// on the compiler.
+#define SB_HASH_NAMESPACE __gnu_cxx
+
+// The location to include hash_set on this platform.
+#define SB_HASH_SET_INCLUDE <ext/hash_set>
+
+// Define this to how this platform copies varargs blocks.
+#define SB_VA_COPY(dest, source) va_copy(dest, source)
+
+// --- Filesystem Configuration ----------------------------------------------
+
+// The current platform's maximum length of the name of a single directory
+// entry, not including the absolute path.
+#define SB_FILE_MAX_NAME 64
+
+// The current platform's maximum length of an absolute path.
+#define SB_FILE_MAX_PATH 4096
+
+// The current platform's maximum number of files that can be opened at the
+// same time by one process.
+#define SB_FILE_MAX_OPEN 64
+
+// The current platform's file path component separator character. This is the
+// character that appears after a directory in a file path. For example, the
+// absolute canonical path of the file "/path/to/a/file.txt" uses '/' as a path
+// component separator character.
+#define SB_FILE_SEP_CHAR '/'
+
+// The current platform's alternate file path component separator character.
+// This is like SB_FILE_SEP_CHAR, except if your platform supports an alternate
+// character, then you can place that here. For example, on windows machines,
+// the primary separator character is probably '\', but the alternate is '/'.
+#define SB_FILE_ALT_SEP_CHAR '/'
+
+// The current platform's search path component separator character. When
+// specifying an ordered list of absolute paths of directories to search for a
+// given reason, this is the character that appears between entries. For
+// example, the search path of "/etc/search/first:/etc/search/second" uses ':'
+// as a search path component separator character.
+#define SB_PATH_SEP_CHAR ':'
+
+// The string form of SB_FILE_SEP_CHAR.
+#define SB_FILE_SEP_STRING "/"
+
+// The string form of SB_FILE_ALT_SEP_CHAR.
+#define SB_FILE_ALT_SEP_STRING "/"
+
+// The string form of SB_PATH_SEP_CHAR.
+#define SB_PATH_SEP_STRING ":"
+
+// On some platforms the file system stores access times at a coarser
+// granularity than other times. When this quirk is defined, we assume the
+// access time is of 1 day precision.
+#undef SB_HAS_QUIRK_FILESYSTEM_COARSE_ACCESS_TIME
+
+// --- Memory Configuration --------------------------------------------------
+
+// The memory page size, which controls the size of chunks on memory that
+// allocators deal with, and the alignment of those chunks. This doesn't have to
+// be the hardware-defined physical page size, but it should be a multiple of
+// it.
+#define SB_MEMORY_PAGE_SIZE 4096
+
+// Whether this platform has and should use an MMAP function to map physical
+// memory to the virtual address space.
+#define SB_HAS_MMAP 0
+
+// Whether this platform can map executable memory. Implies SB_HAS_MMAP. This is
+// required for platforms that want to JIT.
+#define SB_CAN_MAP_EXECUTABLE_MEMORY 0
+
+// Whether this platform has and should use an growable heap (e.g. with sbrk())
+// to map physical memory to the virtual address space.
+#define SB_HAS_VIRTUAL_REGIONS 0
+
+// Specifies the alignment for IO Buffers, in bytes. Some low-level network APIs
+// may require buffers to have a specific alignment, and this is the place to
+// specify that.
+#define SB_NETWORK_IO_BUFFER_ALIGNMENT 16
+
+// Determines the alignment that allocations should have on this platform.
+#define SB_MALLOC_ALIGNMENT ((size_t)16U)
+
+// Determines the threshhold of allocation size that should be done with mmap
+// (if available), rather than allocated within the core heap.
+#define SB_DEFAULT_MMAP_THRESHOLD ((size_t)(256 * 1024U))
+
+// Defines the path where memory debugging logs should be written to.
+#define SB_MEMORY_LOG_PATH "/tmp/starboard"
+
+// --- Thread Configuration --------------------------------------------------
+
+// Defines the maximum number of simultaneous threads for this platform. Some
+// platforms require sharing thread handles with other kinds of system handles,
+// like mutexes, so we want to keep this managable.
+#define SB_MAX_THREADS 90
+
+// The maximum number of thread local storage keys supported by this platform.
+#define SB_MAX_THREAD_LOCAL_KEYS 512
+
+// The maximum length of the name for a thread, including the NULL-terminator.
+#define SB_MAX_THREAD_NAME_LENGTH 16;
+
+// --- Graphics Configuration ------------------------------------------------
+
+// Specifies whether this platform supports a performant accelerated blitter
+// API. The basic requirement is a scaled, clipped, alpha-blended blit.
+#define SB_HAS_BLITTER 0
+
+// Specifies the preferred byte order of color channels in a pixel. Refer to
+// starboard/configuration.h for the possible values. EGL/GLES platforms should
+// generally prefer a byte order of RGBA, regardless of endianness.
+#define SB_PREFERRED_RGBA_BYTE_ORDER SB_PREFERRED_RGBA_BYTE_ORDER_RGBA
+
+// Indicates whether or not the given platform supports bilinear filtering.
+// This can be checked to enable/disable renderer tests that verify that this is
+// working properly.
+#define SB_HAS_BILINEAR_FILTERING_SUPPORT 1
+
+// Indicates whether or not the given platform supports rendering of NV12
+// textures. These textures typically originate from video decoders.
+#define SB_HAS_NV12_TEXTURE_SUPPORT 0
+
+// Whether the current platform should frequently flip its display buffer.  If
+// this is not required (i.e. SB_MUST_FREQUENTLY_FLIP_DISPLAY_BUFFER is set to
+// 0), then optimizations are enabled so the display buffer is not flipped if
+// the scene hasn't changed.
+#define SB_MUST_FREQUENTLY_FLIP_DISPLAY_BUFFER 0
+
+#define SB_HAS_VIRTUAL_REALITY 0
+
+// --- Media Configuration ---------------------------------------------------
+
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
+#define SB_HAS_PLAYER 1
+
+#if SB_API_VERSION < 4
+// Specifies whether this platform's player will produce an OpenGL texture that
+// the client must draw every frame with its graphics rendering. It may be that
+// we get a texture handle, but cannot perform operations like GlReadPixels on
+// it if it is DRM-protected.
+#define SB_IS_PLAYER_PRODUCING_TEXTURE 0
+
+// Specifies whether this platform's player is composited with a formal
+// compositor, where the client must specify how video is to be composited into
+// the graphicals scene.
+#define SB_IS_PLAYER_COMPOSITED 0
+
+// Specifies whether this platform's player uses a "punch-out" model, where
+// video is rendered to the far background, and the graphics plane is
+// automatically composited on top of the video by the platform. The client must
+// punch an alpha hole out of the graphics plane for video to show through.  In
+// this case, changing the video bounds must be tightly synchronized between the
+// player and the graphics plane.
+#define SB_IS_PLAYER_PUNCHED_OUT 1
+#endif  // SB_API_VERSION < 4
+
+// After a seek is triggerred, the default behavior is to append video frames
+// from the last key frame before the seek time and append audio frames from the
+// seek time because usually all audio frames are key frames.  On platforms that
+// cannot decode video frames without displaying them, this will cause the video
+// being played without audio for several seconds after seeking.  When the
+// following macro is defined, the app will append audio frames start from the
+// timestamp that is before the timestamp of the video key frame being appended.
+#undef SB_HAS_QUIRK_SEEK_TO_KEYFRAME
+
+// dlmalloc will use the ffs intrinsic if available.  Platforms on which this is
+// not available should define the following quirk.
+#undef SB_HAS_QUIRK_NO_FFS
+
+#if SB_API_VERSION >= 4
+
+// The maximum audio bitrate the platform can decode.  The following value
+// equals to 5M bytes per seconds which is more than enough for compressed
+// audio.
+#define SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND (40 * 1024 * 1024)
+
+// The maximum video bitrate the platform can decode.  The following value
+// equals to 25M bytes per seconds which is more than enough for compressed
+// video.
+#define SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND (200 * 1024 * 1024)
+
+#endif  // SB_API_VERSION >= 4
+
+// Specifies whether this platform has webm/vp9 support.  This should be set to
+// non-zero on platforms with webm/vp9 support.
+#define SB_HAS_MEDIA_WEBM_VP9_SUPPORT 0
+
+// Specifies the stack size for threads created inside media stack.  Set to 0 to
+// use the default thread stack size.  Set to non-zero to explicitly set the
+// stack size for media stack threads.
+#define SB_MEDIA_THREAD_STACK_SIZE 0U
+
+// --- Decoder-only Params ---
+
+// Specifies how media buffers must be aligned on this platform as some
+// decoders may have special requirement on the alignment of buffers being
+// decoded.
+#define SB_MEDIA_BUFFER_ALIGNMENT 128U
+
+// Specifies how video frame buffers must be aligned on this platform.
+#define SB_MEDIA_VIDEO_FRAME_ALIGNMENT 256U
+
+// The encoded video frames are compressed in different ways, so their decoding
+// time can vary a lot.  Occasionally a single frame can take longer time to
+// decode than the average time per frame.  The player has to cache some frames
+// to account for such inconsistency.  The number of frames being cached are
+// controlled by SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES and
+// SB_MEDIA_MAXIMUM_VIDEO_FRAMES.
+//
+// Specify the number of video frames to be cached before the playback starts.
+// Note that setting this value too large may increase the playback start delay.
+#define SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES 4
+
+// Specify the number of video frames to be cached during playback.  A large
+// value leads to more stable fps but also causes the app to use more memory.
+#define SB_MEDIA_MAXIMUM_VIDEO_FRAMES 12
+
+// --- Network Configuration -------------------------------------------------
+
+// Specifies whether this platform supports IPV6.
+#define SB_HAS_IPV6 1
+
+// Specifies whether this platform supports pipe.
+#define SB_HAS_PIPE 1
+
+// --- Tuneable Parameters ---------------------------------------------------
+
+// Specifies the network receive buffer size in bytes, set via
+// SbSocketSetReceiveBufferSize().
+//
+// Setting this to 0 indicates that SbSocketSetReceiveBufferSize() should
+// not be called. Use this for OSs (such as Linux) where receive buffer
+// auto-tuning is better.
+//
+// On some platforms, this may affect max TCP window size which may
+// dramatically affect throughput in the presence of latency.
+//
+// If your platform does not have a good TCP auto-tuning mechanism,
+// a setting of (128 * 1024) here is recommended.
+#define SB_NETWORK_RECEIVE_BUFFER_SIZE (0)
+
+// --- User Configuration ----------------------------------------------------
+
+// The maximum number of users that can be signed in at the same time.
+#define SB_USER_MAX_SIGNED_IN 1
+
+// --- Timing API ------------------------------------------------------------
+
+// Whether this platform has an API to retrieve how long the current thread
+// has spent in the executing state.
+#define SB_HAS_TIME_THREAD_NOW 1
+
+// --- Platform Specific Audits ----------------------------------------------
+
+#if !defined(__GNUC__)
+#error "Mock builds need a GCC-like compiler (for the moment)."
+#endif
+
+#endif  // STARBOARD_LINUX_X64X11_MOCK_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/mock/gyp_configuration.gypi b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
new file mode 100644
index 0000000..24a0f14
--- /dev/null
+++ b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
@@ -0,0 +1,175 @@
+# Copyright 2017 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.
+{
+  'variables': {
+    'target_arch': 'x64',
+    'target_os': 'linux',
+
+    # Use a stub rasterizer and graphical setup.
+    'rasterizer_type': 'stub',
+
+    # No GL drivers available.
+    'gl_type': 'none',
+
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs-45',
+
+    'cobalt_enable_jit': 0,
+
+    'cobalt_media_source_2016': 1,
+
+    'platform_libraries': [
+      '-lpthread',
+    ],
+
+    # Define platform specific compiler and linker flags.
+    # Refer to base.gypi for a list of all available variables.
+    'compiler_flags_host': [
+      '-O2',
+    ],
+    'compiler_flags': [
+      # We'll pretend not to be Linux, but Starboard instead.
+      '-U__linux__',
+    ],
+    'linker_flags': [
+    ],
+    'compiler_flags_debug': [
+      '-frtti',
+      '-O0',
+    ],
+    'compiler_flags_devel': [
+      '-frtti',
+      '-O2',
+    ],
+    'compiler_flags_qa': [
+      '-fno-rtti',
+      '-O2',
+      '-gline-tables-only',
+    ],
+    'compiler_flags_gold': [
+      '-fno-rtti',
+      '-O2',
+      '-gline-tables-only',
+    ],
+    'conditions': [
+      ['clang==1', {
+        'common_clang_flags': [
+          '-Werror',
+          '-fcolor-diagnostics',
+          # Default visibility to hidden, to enable dead stripping.
+          '-fvisibility=hidden',
+          # Warn for implicit type conversions that may change a value.
+          '-Wconversion',
+          '-Wno-c++11-compat',
+          # This (rightfully) complains about 'override', which we use
+          # heavily.
+          '-Wno-c++11-extensions',
+          # Warns on switches on enums that cover all enum values but
+          # also contain a default: branch. Chrome is full of that.
+          '-Wno-covered-switch-default',
+          # protobuf uses hash_map.
+          '-Wno-deprecated',
+          '-fno-exceptions',
+          # Don't warn about the "struct foo f = {0};" initialization pattern.
+          '-Wno-missing-field-initializers',
+          # Do not warn for implicit sign conversions.
+          '-Wno-sign-conversion',
+          '-fno-strict-aliasing',  # See http://crbug.com/32204
+          # TODO(pkasting): In C++11 this is legal, so this should be
+          # removed when we change to that.  (This is also why we don't
+          # bother fixing all these cases today.)
+          '-Wno-unnamed-type-template-args',
+          # Triggered by the COMPILE_ASSERT macro.
+          '-Wno-unused-local-typedef',
+          # Do not warn if a function or variable cannot be implicitly
+          # instantiated.
+          '-Wno-undefined-var-template',
+        ],
+      }],
+      ['cobalt_fastbuild==0', {
+        'compiler_flags_debug': [
+          '-g',
+        ],
+        'compiler_flags_devel': [
+          '-g',
+        ],
+        'compiler_flags_qa': [
+          '-gline-tables-only',
+        ],
+        'compiler_flags_gold': [
+          '-gline-tables-only',
+        ],
+      }],
+    ],
+  },
+
+  'target_defaults': {
+    'defines': [
+      '__STDC_FORMAT_MACROS', # so that we get PRI*
+      # Enable GNU extensions to get prototypes like ffsl.
+      #'_GNU_SOURCE=1',
+    ],
+    'cflags_c': [
+      # Limit to C99. This allows stub to be a canary build for any
+      # C11 features that are not supported on some platforms' compilers.
+      #'-std=c99',
+    ],
+    'cflags_cc': [
+      '-std=gnu++11',
+    ],
+    'default_configuration': 'linux-x64x11-mock_debug',
+    'configurations': {
+      'linux-x64x11-mock_debug': {
+        'inherit_from': ['debug_base'],
+      },
+      'linux-x64x11-mock_devel': {
+        'inherit_from': ['devel_base'],
+      },
+      'linux-x64x11-mock_qa': {
+        'inherit_from': ['qa_base'],
+      },
+      'linux-x64x11-mock_gold': {
+        'inherit_from': ['gold_base'],
+      },
+    }, # end of configurations
+    'target_conditions': [
+      ['cobalt_code==1', {
+        'cflags': [
+          '-Wall',
+          '-Wextra',
+          '-Wunreachable-code',
+          '<@(common_clang_flags)',
+        ],
+      },{
+        'cflags': [
+          '<@(common_clang_flags)',
+          # 'this' pointer cannot be NULL...pointer may be assumed
+          # to always convert to true.
+          '-Wno-undefined-bool-conversion',
+          # Skia doesn't use overrides.
+          '-Wno-inconsistent-missing-override',
+          # Do not warn about unused function params.
+          '-Wno-unused-parameter',
+          # Do not warn for implicit type conversions that may change a value.
+          '-Wno-conversion',
+          # shifting a negative signed value is undefined
+          '-Wno-shift-negative-value',
+          # Width of bit-field exceeds width of its type- value will be truncated
+          '-Wno-bitfield-width',
+        ],
+      }],
+    ],
+  }, # end of target_defaults
+}
diff --git a/src/starboard/linux/x64x11/mock/gyp_configuration.py b/src/starboard/linux/x64x11/mock/gyp_configuration.py
new file mode 100644
index 0000000..ff41cea
--- /dev/null
+++ b/src/starboard/linux/x64x11/mock/gyp_configuration.py
@@ -0,0 +1,58 @@
+# Copyright 2017 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.
+"""Starboard mock platform configuration for gyp_cobalt."""
+
+import logging
+
+import config.starboard
+import gyp_utils
+
+
+def CreatePlatformConfig():
+  try:
+    return PlatformConfig('linux-x64x11-mock')
+  except RuntimeError as e:
+    logging.critical(e)
+    return None
+
+
+class PlatformConfig(config.starboard.PlatformConfigStarboard):
+  """Starboard mock platform configuration."""
+
+  def __init__(self, platform):
+    super(PlatformConfig, self).__init__(platform)
+    goma_supports_compiler = True
+    self.host_compiler_environment = gyp_utils.GetHostCompilerEnvironment(
+        goma_supports_compiler)
+
+  def GetBuildFormat(self):
+    return 'ninja,qtcreator_ninja'
+
+  def GetVariables(self, configuration):
+    return super(PlatformConfig, self).GetVariables(configuration, use_clang=1)
+
+  def GetGeneratorVariables(self, configuration):
+    _ = configuration
+    generator_variables = {
+        'qtcreator_session_name_prefix': 'cobalt',
+    }
+    return generator_variables
+
+  def GetEnvironmentVariables(self):
+    env_variables = self.host_compiler_environment
+    env_variables.update({
+        'CC': self.host_compiler_environment['CC_host'],
+        'CXX': self.host_compiler_environment['CXX_host'],
+    })
+    return env_variables
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/linux/x64x11/mock/main.cc
similarity index 68%
copy from src/starboard/raspi/1/atomic_public.h
copy to src/starboard/linux/x64x11/mock/main.cc
index 6fa6273..8210c1f 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/linux/x64x11/mock/main.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#include "starboard/configuration.h"
+#include "starboard/stub/application_stub.h"
 
-#include "starboard/raspi/shared/atomic_public.h"
-
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+int main(int argc, char** argv) {
+  starboard::stub::ApplicationStub application;
+  return application.Run(argc, argv);
+}
diff --git a/src/starboard/linux/x64x11/mock/starboard_platform.gyp b/src/starboard/linux/x64x11/mock/starboard_platform.gyp
new file mode 100644
index 0000000..3b233a6
--- /dev/null
+++ b/src/starboard/linux/x64x11/mock/starboard_platform.gyp
@@ -0,0 +1,280 @@
+# Copyright 2017 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': 'starboard_platform',
+      'type': 'static_library',
+      'sources': [
+        # TODO: Convert all stubs to mocks.
+        '<(DEPTH)/starboard/shared/stub/accessibility_get_display_settings.cc',
+        '<(DEPTH)/starboard/shared/stub/accessibility_get_text_to_speech_settings.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_create.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_get_max_channels.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_get_nearest_supported_sample_frequency.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_audio_frame_storage_type_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_audio_sample_type_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_valid.cc',
+        '<(DEPTH)/starboard/shared/stub/byte_swap.cc',
+        '<(DEPTH)/starboard/shared/stub/character_is_alphanumeric.cc',
+        '<(DEPTH)/starboard/shared/stub/character_is_digit.cc',
+        '<(DEPTH)/starboard/shared/stub/character_is_hex_digit.cc',
+        '<(DEPTH)/starboard/shared/stub/character_is_space.cc',
+        '<(DEPTH)/starboard/shared/stub/character_is_upper.cc',
+        '<(DEPTH)/starboard/shared/stub/character_to_lower.cc',
+        '<(DEPTH)/starboard/shared/stub/character_to_upper.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_broadcast.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_create.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_signal.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_wait.cc',
+        '<(DEPTH)/starboard/shared/stub/condition_variable_wait_timed.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_create_transformer.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_destroy_transformer.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_get_tag.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_set_authenticated_data.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_set_initialization_vector.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_transform.cc',
+        '<(DEPTH)/starboard/shared/stub/directory_can_open.cc',
+        '<(DEPTH)/starboard/shared/stub/directory_close.cc',
+        '<(DEPTH)/starboard/shared/stub/directory_create.cc',
+        '<(DEPTH)/starboard/shared/stub/directory_get_next.cc',
+        '<(DEPTH)/starboard/shared/stub/directory_open.cc',
+        '<(DEPTH)/starboard/shared/stub/double_absolute.cc',
+        '<(DEPTH)/starboard/shared/stub/double_exponent.cc',
+        '<(DEPTH)/starboard/shared/stub/double_floor.cc',
+        '<(DEPTH)/starboard/shared/stub/double_is_finite.cc',
+        '<(DEPTH)/starboard/shared/stub/double_is_nan.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_close_session.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_create_system.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
+        '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
+        '<(DEPTH)/starboard/shared/stub/file_can_open.cc',
+        '<(DEPTH)/starboard/shared/stub/file_close.cc',
+        '<(DEPTH)/starboard/shared/stub/file_delete.cc',
+        '<(DEPTH)/starboard/shared/stub/file_exists.cc',
+        '<(DEPTH)/starboard/shared/stub/file_flush.cc',
+        '<(DEPTH)/starboard/shared/stub/file_get_info.cc',
+        '<(DEPTH)/starboard/shared/stub/file_get_path_info.cc',
+        '<(DEPTH)/starboard/shared/stub/file_open.cc',
+        '<(DEPTH)/starboard/shared/stub/file_read.cc',
+        '<(DEPTH)/starboard/shared/stub/file_seek.cc',
+        '<(DEPTH)/starboard/shared/stub/file_truncate.cc',
+        '<(DEPTH)/starboard/shared/stub/file_write.cc',
+        '<(DEPTH)/starboard/shared/stub/media_can_play_mime_and_key_system.cc',
+        '<(DEPTH)/starboard/shared/stub/media_get_audio_configuration.cc',
+        '<(DEPTH)/starboard/shared/stub/media_get_audio_output_count.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_audio_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_output_protected.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_transfer_characteristics_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_video_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_close.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_create.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_get_available.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_is_sample_rate_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_open.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_read.cc',
+        '<(DEPTH)/starboard/shared/stub/mutex_acquire.cc',
+        '<(DEPTH)/starboard/shared/stub/mutex_acquire_try.cc',
+        '<(DEPTH)/starboard/shared/stub/mutex_create.cc',
+        '<(DEPTH)/starboard/shared/stub/mutex_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/mutex_release.cc',
+        '<(DEPTH)/starboard/shared/stub/once.cc',
+        '<(DEPTH)/starboard/shared/stub/player_create.cc',
+        '<(DEPTH)/starboard/shared/stub/player_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/player_get_current_frame.cc',
+        '<(DEPTH)/starboard/shared/stub/player_get_info.cc',
+        '<(DEPTH)/starboard/shared/stub/player_output_mode_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/player_seek.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_bounds.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_pause.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_playback_rate.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_volume.cc',
+        '<(DEPTH)/starboard/shared/stub/player_write_end_of_stream.cc',
+        '<(DEPTH)/starboard/shared/stub/player_write_sample.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_accept.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_bind.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_clear_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_connect.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_create.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_free_resolution.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_get_interface_address.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_get_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_get_local_address.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_get_local_interface_address.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_is_connected.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_is_connected_and_idle.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_join_multicast_group.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_listen.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_receive_from.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_resolve.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_send_to.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_broadcast.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_receive_buffer_size.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_reuse_address.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_send_buffer_size.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_tcp_keep_alive.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_tcp_no_delay.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_set_tcp_window_scaling.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_add.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_create.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_remove.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait_timed.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wake_up.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_recognizer_cancel.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_recognizer_create.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_recognizer_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_recognizer_start.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_recognizer_stop.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_synthesis_cancel.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_synthesis_set_language.cc',
+        '<(DEPTH)/starboard/shared/stub/speech_synthesis_speak.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_close_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_delete_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_get_record_size.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_open_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_read_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_write_record.cc',
+        '<(DEPTH)/starboard/shared/stub/string_compare.cc',
+        '<(DEPTH)/starboard/shared/stub/string_compare_all.cc',
+        '<(DEPTH)/starboard/shared/stub/string_compare_no_case.cc',
+        '<(DEPTH)/starboard/shared/stub/string_compare_no_case_n.cc',
+        '<(DEPTH)/starboard/shared/stub/string_compare_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_concat.cc',
+        '<(DEPTH)/starboard/shared/stub/string_concat_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_copy.cc',
+        '<(DEPTH)/starboard/shared/stub/string_copy_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_duplicate.cc',
+        '<(DEPTH)/starboard/shared/stub/string_find_character.cc',
+        '<(DEPTH)/starboard/shared/stub/string_find_last_character.cc',
+        '<(DEPTH)/starboard/shared/stub/string_find_string.cc',
+        '<(DEPTH)/starboard/shared/stub/string_format.cc',
+        '<(DEPTH)/starboard/shared/stub/string_format_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_get_length.cc',
+        '<(DEPTH)/starboard/shared/stub/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/stub/string_parse_double.cc',
+        '<(DEPTH)/starboard/shared/stub/string_parse_signed_integer.cc',
+        '<(DEPTH)/starboard/shared/stub/string_parse_uint64.cc',
+        '<(DEPTH)/starboard/shared/stub/string_parse_unsigned_integer.cc',
+        '<(DEPTH)/starboard/shared/stub/string_scan.cc',
+        '<(DEPTH)/starboard/shared/stub/system_binary_search.cc',
+        '<(DEPTH)/starboard/shared/stub/system_break_into_debugger.cc',
+        '<(DEPTH)/starboard/shared/stub/system_clear_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_connection_type.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_device_type.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_error_string.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_locale_id.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_number_of_processors.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_path.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_property.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_random_data.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_random_uint64.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_stack.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_total_cpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_total_gpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_used_cpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_used_gpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_has_capability.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
+        '<(DEPTH)/starboard/shared/stub/system_is_debugger_attached.cc',
+        '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_pause.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_suspend.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_unpause.cc',
+        '<(DEPTH)/starboard/shared/stub/system_sort.cc',
+        '<(DEPTH)/starboard/shared/stub/system_symbolize.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_create.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_create_local_key.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_destroy_local_key.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_detach.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_get_current.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_get_id.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_get_local_value.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_get_name.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_is_equal.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_join.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_set_local_value.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_set_name.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_sleep.cc',
+        '<(DEPTH)/starboard/shared/stub/thread_types_public.h',
+        '<(DEPTH)/starboard/shared/stub/thread_yield.cc',
+        '<(DEPTH)/starboard/shared/stub/time_get_monotonic_now.cc',
+        '<(DEPTH)/starboard/shared/stub/time_get_monotonic_thread_now.cc',
+        '<(DEPTH)/starboard/shared/stub/time_get_now.cc',
+        '<(DEPTH)/starboard/shared/stub/time_zone_get_current.cc',
+        '<(DEPTH)/starboard/shared/stub/time_zone_get_dst_name.cc',
+        '<(DEPTH)/starboard/shared/stub/time_zone_get_name.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_current.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_property.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_signed_in.cc',
+        '<(DEPTH)/starboard/shared/stub/window_create.cc',
+        '<(DEPTH)/starboard/shared/stub/window_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
+        '<(DEPTH)/starboard/shared/stub/window_get_size.cc',
+        '<(DEPTH)/starboard/shared/stub/window_set_default_options.cc',
+
+        # Minimal Starboard implementation that allows to run unit tests.
+        '<(DEPTH)/starboard/linux/shared/atomic_public.h',
+        '<(DEPTH)/starboard/shared/iso/memory_allocate_unchecked.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_compare.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_copy.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_find_byte.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_free.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_move.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_reallocate_unchecked.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_set.cc',
+        '<(DEPTH)/starboard/shared/linux/memory_get_stack_bounds.cc',
+        '<(DEPTH)/starboard/shared/posix/log.cc',
+        '<(DEPTH)/starboard/shared/posix/log_flush.cc',
+        '<(DEPTH)/starboard/shared/posix/log_format.cc',
+        '<(DEPTH)/starboard/shared/posix/log_is_tty.cc',
+        '<(DEPTH)/starboard/shared/posix/log_raw.cc',
+        '<(DEPTH)/starboard/shared/posix/memory_allocate_aligned_unchecked.cc',
+        '<(DEPTH)/starboard/shared/posix/memory_free_aligned.cc',
+        '<(DEPTH)/starboard/shared/starboard/application.cc',
+        '<(DEPTH)/starboard/shared/starboard/command_line.cc',
+        '<(DEPTH)/starboard/shared/starboard/command_line.h',
+        '<(DEPTH)/starboard/shared/starboard/event_cancel.cc',
+        '<(DEPTH)/starboard/shared/starboard/event_schedule.cc',
+        '<(DEPTH)/starboard/shared/starboard/file_mode_string_to_flags.cc',
+        '<(DEPTH)/starboard/shared/starboard/log_message.cc',
+        '<(DEPTH)/starboard/shared/starboard/log_raw_dump_stack.cc',
+        '<(DEPTH)/starboard/shared/starboard/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
+        '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+        '<(DEPTH)/starboard/stub/application_stub.cc',
+        '<(DEPTH)/starboard/stub/application_stub.h',
+        'atomic_public.h',
+        'main.cc',
+        'thread_types_public.h',
+      ],
+      'defines': [
+        # This must be defined when building Starboard, and must not when
+        # building Starboard client code.
+        'STARBOARD_IMPLEMENTATION',
+      ],
+    },
+  ],
+}
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/linux/x64x11/mock/thread_types_public.h
similarity index 62%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/linux/x64x11/mock/thread_types_public.h
index ba3f4ad..af87de9 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/linux/x64x11/mock/thread_types_public.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+// Includes threading primitive types and initializers.
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#ifndef STARBOARD_LINUX_X64X11_MOCK_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_MOCK_THREAD_TYPES_PUBLIC_H_
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/shared/stub/thread_types_public.h"
+
+#endif  // STARBOARD_LINUX_X64X11_MOCK_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/log.h b/src/starboard/log.h
index 252f7ae..596bc88 100644
--- a/src/starboard/log.h
+++ b/src/starboard/log.h
@@ -221,24 +221,29 @@
 #if SB_LOGGING_IS_OFFICIAL_BUILD
 #define SB_CHECK(condition) \
   !(condition) ? ::starboard::logging::Break() : SB_EAT_STREAM_PARAMETERS
-#define SB_DCHECK(condition) SB_EAT_STREAM_PARAMETERS
 #elif defined(_PREFAST_)
 #define SB_CHECK(condition) \
   __analysis_assume(condition), SB_EAT_STREAM_PARAMETERS
-#define SB_DCHECK(condition) SB_CHECK(condition)
 #else
 #define SB_CHECK(condition) \
   SB_LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
-#define SB_DCHECK(condition) SB_CHECK(condition)
 #endif  // SB_LOGGING_IS_OFFICIAL_BUILD
 
-#if SB_LOGGING_IS_OFFICIAL_BUILD
+#if SB_LOGGING_IS_OFFICIAL_BUILD || \
+    (defined(NDEBUG) && !defined(__LB_SHELL__FORCE_LOGGING__))
 #define SB_DLOG_IS_ON(severity) false
 #define SB_DLOG_IF(severity, condition) SB_EAT_STREAM_PARAMETERS
-#else  // SB_LOGGING_IS_OFFICIAL_BUILD
+#else
 #define SB_DLOG_IS_ON(severity) SB_LOG_IS_ON(severity)
 #define SB_DLOG_IF(severity, condition) SB_LOG_IF(severity, condition)
-#endif  // SB_LOGGING_IS_OFFICIAL_BUILD
+#endif
+
+#if SB_LOGGING_IS_OFFICIAL_BUILD || \
+    (defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
+#define SB_DCHECK(condition) SB_EAT_STREAM_PARAMETERS
+#else
+#define SB_DCHECK(condition) SB_CHECK(condition)
+#endif
 
 #define SB_DLOG(severity) SB_DLOG_IF(severity, SB_DLOG_IS_ON(severity))
 #define SB_DSTACK(severity) SB_STACK_IF(severity, SB_DLOG_IS_ON(severity))
diff --git a/src/starboard/media.h b/src/starboard/media.h
index a58e369..4767c4d 100644
--- a/src/starboard/media.h
+++ b/src/starboard/media.h
@@ -466,7 +466,11 @@
 
   // The AudioSpecificConfig, as specified in ISO/IEC-14496-3, section 1.6.2.1:
   // http://read.pudn.com/downloads98/doc/comm/401153/14496/ISO_IEC_14496-3%20Part%203%20Audio/C036083E_SUB1.PDF
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  const void* audio_specific_config;
+#else   // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
   int8_t audio_specific_config[8];
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
 } SbMediaAudioHeader;
 
 // --- Constants -------------------------------------------------------------
diff --git a/src/starboard/nplb/memory_reporter_test.cc b/src/starboard/nplb/memory_reporter_test.cc
index d60e010..d4dfddf 100644
--- a/src/starboard/nplb/memory_reporter_test.cc
+++ b/src/starboard/nplb/memory_reporter_test.cc
@@ -320,6 +320,7 @@
   EXPECT_EQ_NO_TRACKING(mem_reporter()->number_allocs(), 0);
 }
 
+#if SB_HAS(MMAP)
 // Tests the assumption that the SbMemoryMap and SbMemoryUnmap
 // will report memory allocations.
 TEST_F(MemoryReportingTest, CapturesMemMapUnmap) {
@@ -339,6 +340,7 @@
   EXPECT_EQ_NO_TRACKING(mem_chunk, mem_reporter()->last_mem_unmap());
   EXPECT_EQ_NO_TRACKING(0, mem_reporter()->number_allocs());
 }
+#endif  // SB_HAS(MMAP)
 
 // Tests the assumption that the operator/delete will report
 // memory allocations.
diff --git a/src/starboard/nplb/player_create_test.cc b/src/starboard/nplb/player_create_test.cc
index 3bff176..9523d89 100644
--- a/src/starboard/nplb/player_create_test.cc
+++ b/src/starboard/nplb/player_create_test.cc
@@ -60,6 +60,9 @@
   audio_header.block_alignment = 4;
   audio_header.bits_per_sample = 32;
   audio_header.audio_specific_config_size = 0;
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  audio_header.audio_specific_config = NULL;
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
   audio_header.average_bytes_per_second = audio_header.samples_per_second *
                                           audio_header.number_of_channels *
                                           audio_header.bits_per_sample / 8;
diff --git a/src/starboard/nplb/time_zone_get_dst_name_test.cc b/src/starboard/nplb/time_zone_get_dst_name_test.cc
index 3da665d..d2926b5 100644
--- a/src/starboard/nplb/time_zone_get_dst_name_test.cc
+++ b/src/starboard/nplb/time_zone_get_dst_name_test.cc
@@ -20,6 +20,7 @@
 namespace nplb {
 namespace {
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 TEST(SbTimeZoneGetDstNameTest, IsKindOfSane) {
   const char* name = SbTimeZoneGetDstName();
 
@@ -34,6 +35,7 @@
   EXPECT_GE(i, 3);
   EXPECT_LE(i, 5);
 }
+#endif  // SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 
 }  // namespace
 }  // namespace nplb
diff --git a/src/starboard/nplb/time_zone_get_name_test.cc b/src/starboard/nplb/time_zone_get_name_test.cc
index 16e782f..41b7d5e 100644
--- a/src/starboard/nplb/time_zone_get_name_test.cc
+++ b/src/starboard/nplb/time_zone_get_name_test.cc
@@ -30,14 +30,16 @@
     ++i;
   }
 
-  // Most time zones are 3 letters.
-  // I haven't been able to get Linux to produce a 2 or 1 letter time zone.
+  // All time zones are 3 letters or more. This can include names like "PST"
+  // or "Pacific Standard Time" or like "America/Los_Angeles"
   EXPECT_GE(i, 3);
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
   // Some, like WART for Western Argentina, are 4.
   // A very few, like ANAST, or CHAST is 5
   // http://www.timeanddate.com/time/zones/
   EXPECT_LE(i, 5);
+#endif  // SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 
   // On Linux, TZ=":Pacific/Chatham" is a good test of boundary conditions.
   // ":Pacific/Kiritimati" is the western-most timezone at UTC+14.
diff --git a/src/starboard/player.h b/src/starboard/player.h
index 5335bd9..a58b683 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -253,6 +253,11 @@
 // |audio_header|: Note that the caller must provide a populated |audio_header|
 //   if the audio codec is |kSbMediaAudioCodecAac|. Otherwise, |audio_header|
 //   can be NULL. See media.h for the format of the |SbMediaAudioHeader| struct.
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+//   Note that |audio_specific_config| is a pointer and the content it points to
+//   is no longer valid after this function returns.  The implementation has to
+//   make a copy of the content if it is needed after the function returns.
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
 //
 // |sample_deallocator_func|: If not |NULL|, the player calls this function
 //   on an internal thread to free the sample buffers passed into
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/raspi/0/atomic_public.h
similarity index 83%
rename from src/starboard/raspi/1/atomic_public.h
rename to src/starboard/raspi/0/atomic_public.h
index 6fa6273..19d9b71 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/raspi/0/atomic_public.h
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#ifndef STARBOARD_RASPI_0_ATOMIC_PUBLIC_H_
+#define STARBOARD_RASPI_0_ATOMIC_PUBLIC_H_
 
 #include "starboard/raspi/shared/atomic_public.h"
 
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#endif  // STARBOARD_RASPI_0_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/raspi/1/configuration_public.h b/src/starboard/raspi/0/configuration_public.h
similarity index 95%
rename from src/starboard/raspi/1/configuration_public.h
rename to src/starboard/raspi/0/configuration_public.h
index 3cedc59..b1352a0 100644
--- a/src/starboard/raspi/1/configuration_public.h
+++ b/src/starboard/raspi/0/configuration_public.h
@@ -17,8 +17,8 @@
 // Other source files should never include this header directly, but should
 // include the generic "starboard/configuration.h" instead.
 
-#ifndef STARBOARD_RASPI_1_CONFIGURATION_PUBLIC_H_
-#define STARBOARD_RASPI_1_CONFIGURATION_PUBLIC_H_
+#ifndef STARBOARD_RASPI_0_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_RASPI_0_CONFIGURATION_PUBLIC_H_
 
 // --- Architecture Configuration --------------------------------------------
 
@@ -92,4 +92,4 @@
 
 #include "starboard/raspi/shared/configuration_public.h"
 
-#endif  // STARBOARD_RASPI_1_CONFIGURATION_PUBLIC_H_
+#endif  // STARBOARD_RASPI_0_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/0/gyp_configuration.gypi
similarity index 89%
rename from src/starboard/raspi/1/gyp_configuration.gypi
rename to src/starboard/raspi/0/gyp_configuration.gypi
index f76edaf..ff3100b 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/0/gyp_configuration.gypi
@@ -31,18 +31,18 @@
   },
 
   'target_defaults': {
-    'default_configuration': 'raspi-1_debug',
+    'default_configuration': 'raspi-0_debug',
     'configurations': {
-      'raspi-1_debug': {
+      'raspi-0_debug': {
         'inherit_from': ['debug_base'],
       },
-      'raspi-1_devel': {
+      'raspi-0_devel': {
         'inherit_from': ['devel_base'],
       },
-      'raspi-1_qa': {
+      'raspi-0_qa': {
         'inherit_from': ['qa_base'],
       },
-      'raspi-1_gold': {
+      'raspi-0_gold': {
         'inherit_from': ['gold_base'],
       },
     }, # end of configurations
diff --git a/src/starboard/raspi/1/gyp_configuration.py b/src/starboard/raspi/0/gyp_configuration.py
similarity index 89%
rename from src/starboard/raspi/1/gyp_configuration.py
rename to src/starboard/raspi/0/gyp_configuration.py
index 2f7e9c5..b36cab7 100644
--- a/src/starboard/raspi/1/gyp_configuration.py
+++ b/src/starboard/raspi/0/gyp_configuration.py
@@ -11,7 +11,7 @@
 # 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.
-"""Starboard Raspberry Pi 1 platform configuration for gyp_cobalt."""
+"""Starboard Raspberry Pi 0 platform configuration for gyp_cobalt."""
 
 import logging
 import os
@@ -26,7 +26,7 @@
 
 def CreatePlatformConfig():
   try:
-    return RaspiPlatformConfig('raspi-1')
+    return RaspiPlatformConfig('raspi-0')
   except RuntimeError as e:
     logging.critical(e)
     return None
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/0/starboard_platform.gyp
similarity index 100%
rename from src/starboard/raspi/1/starboard_platform.gyp
rename to src/starboard/raspi/0/starboard_platform.gyp
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/raspi/0/thread_types_public.h
similarity index 81%
rename from src/starboard/raspi/1/thread_types_public.h
rename to src/starboard/raspi/0/thread_types_public.h
index ba3f4ad..d4d6721 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/raspi/0/thread_types_public.h
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#ifndef STARBOARD_RASPI_0_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_RASPI_0_THREAD_TYPES_PUBLIC_H_
 
 #include "starboard/raspi/shared/thread_types_public.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#endif  // STARBOARD_RASPI_0_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/raspi/directfb/README.md b/src/starboard/raspi/directfb/README.md
index a4b4ec7..28452a6 100644
--- a/src/starboard/raspi/directfb/README.md
+++ b/src/starboard/raspi/directfb/README.md
@@ -2,7 +2,7 @@
 
 Starboard's Blitter API contains a DirectFB implementation.  There does not
 currently exist a supported Starboard configuration for DirectFB on the
-Raspberry Pi, but it can be created easily by copying the raspi-1 configuration
+Raspberry Pi, but it can be created easily by copying the raspi-0 configuration
 and modifying the setup to use the Blitter API with DirectFB instead of Dispmanx
 and EGL/GLES2.
 
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
index a74b0b3..893d2a0 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
@@ -42,6 +42,9 @@
   void Reset() SB_OVERRIDE;
   SbMediaAudioSampleType GetSampleType() const SB_OVERRIDE;
   int GetSamplesPerSecond() const SB_OVERRIDE;
+  bool CanAcceptMoreData() const SB_OVERRIDE {
+    return !stream_ended_ && decoded_audios_.size() <= kMaxDecodedAudiosSize;
+  }
 
   bool is_valid() const { return codec_context_ != NULL; }
 
@@ -49,6 +52,8 @@
   void InitializeCodec();
   void TeardownCodec();
 
+  static const int kMaxDecodedAudiosSize = 64;
+
   SbMediaAudioCodec audio_codec_;
   SbMediaAudioSampleType sample_type_;
   AVCodecContext* codec_context_;
diff --git a/src/starboard/shared/posix/time_zone_get_dst_name.cc b/src/starboard/shared/posix/time_zone_get_dst_name.cc
index 17c7f44..97683f9 100644
--- a/src/starboard/shared/posix/time_zone_get_dst_name.cc
+++ b/src/starboard/shared/posix/time_zone_get_dst_name.cc
@@ -16,9 +16,11 @@
 
 #include <time.h>
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 const char* SbTimeZoneGetDstName() {
   // TODO: Using tzname assumes that tzset() has been called at some
   // point. That should happen as part of Starboard's main loop initialization,
   // but that doesn't exist yet.
   return tzname[1];
 }
+#endif  // SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
diff --git a/src/starboard/shared/signal/signal_internal.h b/src/starboard/shared/signal/signal_internal.h
index 0d2ec54..a1f095c 100644
--- a/src/starboard/shared/signal/signal_internal.h
+++ b/src/starboard/shared/signal/signal_internal.h
@@ -52,6 +52,10 @@
       return "SIGTSTP";
     case SIGTERM:
       return "SIGTERM";
+    case SIGUSR1:
+      return "SIGUSR1";
+    case SIGUSR2:
+      return "SIGUSR2";
     default:
       return "UNKNOWN";
   }
diff --git a/src/starboard/shared/signal/suspend_signals.cc b/src/starboard/shared/signal/suspend_signals.cc
index cd1bb79..490b0ed 100644
--- a/src/starboard/shared/signal/suspend_signals.cc
+++ b/src/starboard/shared/signal/suspend_signals.cc
@@ -50,6 +50,7 @@
 }
 
 void SuspendDone(void* /*context*/) {
+  // Stop all thread execution after fully transitioning into Suspended.
   raise(SIGSTOP);
 }
 
@@ -88,12 +89,17 @@
   // log messages may behave in surprising ways, so it's not desirable.
   SetSignalHandler(SIGPIPE, &Ignore);
 #endif
+  SetSignalHandler(SIGUSR1, &Suspend);
+  UnblockSignal(SIGUSR1);
+  SetSignalHandler(SIGCONT, &Resume);
 }
 
 void UninstallSuspendSignalHandlers() {
 #if !defined(MSG_NOSIGNAL)
   SetSignalHandler(SIGPIPE, SIG_DFL);
 #endif
+  SetSignalHandler(SIGUSR1, SIG_DFL);
+  SetSignalHandler(SIGCONT, SIG_DFL);
 }
 
 }  // namespace signal
diff --git a/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h b/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
index 0ea8d68..bb501f1 100644
--- a/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
@@ -58,6 +58,9 @@
   // audio renderer as the sample rate of the underlying audio stream can be
   // different than the sample rate stored in the meta data.
   virtual int GetSamplesPerSecond() const = 0;
+
+  // Return whether the decoder can accept more data or not.
+  virtual bool CanAcceptMoreData() const = 0;
 };
 
 }  // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index 7041009..dac6b06 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -53,8 +53,7 @@
       end_of_stream_decoded_(false),
       decoder_(decoder.Pass()),
       audio_sink_(kSbAudioSinkInvalid),
-      decoder_needs_full_reset_(false),
-      buffers_in_decoder_(0) {
+      decoder_needs_full_reset_(false) {
   SB_DCHECK(job_queue != NULL);
   SB_DCHECK(decoder_ != NULL);
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
@@ -104,7 +103,6 @@
   decoder_->Decode(input_buffer);
 
   ScopedLock lock(mutex_);
-  buffers_in_decoder_++;
   decoder_needs_full_reset_ = true;
   if (!read_from_decoder_closure_.is_valid()) {
     read_from_decoder_closure_ =
@@ -125,7 +123,6 @@
   decoder_->WriteEndOfStream();
 
   ScopedLock lock(mutex_);
-  buffers_in_decoder_++;
   end_of_stream_written_ = true;
   decoder_needs_full_reset_ = true;
   // If we are seeking, we consider the seek is finished if end of stream is
@@ -179,7 +176,6 @@
   end_of_stream_written_ = false;
   end_of_stream_decoded_ = false;
   pending_decoded_audio_ = NULL;
-  buffers_in_decoder_ = 0;
 
   if (decoder_needs_full_reset_) {
     decoder_->Reset();
@@ -197,11 +193,13 @@
 bool AudioRendererImpl::CanAcceptMoreData() const {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
-  ScopedLock lock(mutex_);
-  if (end_of_stream_written_) {
-    return false;
+  {
+    ScopedLock lock(mutex_);
+    if (end_of_stream_written_) {
+      return false;
+    }
   }
-  return buffers_in_decoder_ < kMaxbuffersInDecoder;
+  return decoder_->CanAcceptMoreData();
 }
 
 bool AudioRendererImpl::IsSeekingInProgress() const {
@@ -307,10 +305,6 @@
     decoded_audio = pending_decoded_audio_;
   } else {
     decoded_audio = decoder_->Read();
-    if (decoded_audio) {
-      SB_DCHECK(buffers_in_decoder_ > 0);
-      buffers_in_decoder_--;
-    }
   }
   pending_decoded_audio_ = NULL;
   if (!decoded_audio) {
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
index 3e50194..ac90e0a 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -73,9 +73,6 @@
   // 2. Have the audio cache full to simulate the state that the renderer can
   //    no longer accept more data.
   static const size_t kMaxCachedFrames = 256 * 1024;
-  // When there are more than |kMaxBuffersInDecoder| buffers inside the audio
-  // decoder, the renderer won't accept more data.
-  static const int kMaxbuffersInDecoder = 32;
 
   void UpdateSourceStatus(int* frames_in_buffer,
                           int* offset_in_frames,
@@ -129,8 +126,6 @@
   // performance by keeping track of whether we already have a fresh decoder,
   // and can thus avoid doing a full reset.
   bool decoder_needs_full_reset_;
-
-  int buffers_in_decoder_;
 };
 
 }  // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/ffmpeg_player_components_impl.cc b/src/starboard/shared/starboard/player/filter/ffmpeg_player_components_impl.cc
index e5c1529..5b19b46 100644
--- a/src/starboard/shared/starboard/player/filter/ffmpeg_player_components_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/ffmpeg_player_components_impl.cc
@@ -14,6 +14,7 @@
 
 #include "starboard/shared/starboard/player/filter/player_components.h"
 
+#include "starboard/audio_sink.h"
 #include "starboard/shared/ffmpeg/ffmpeg_audio_decoder.h"
 #include "starboard/shared/ffmpeg/ffmpeg_video_decoder.h"
 #include "starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h"
@@ -32,6 +33,14 @@
   typedef ::starboard::shared::ffmpeg::AudioDecoder AudioDecoderImpl;
   typedef ::starboard::shared::ffmpeg::VideoDecoder VideoDecoderImpl;
 
+  // TODO: This is not ideal as we should really handle the creation failure of
+  // audio sink inside the audio renderer to give the renderer a chance to
+  // resample the decoded audio.
+  const int audio_channels = audio_parameters.audio_header.number_of_channels;
+  if (audio_channels > SbAudioSinkGetMaxChannels()) {
+    return scoped_ptr<PlayerComponents>(NULL);
+  }
+
   AudioDecoderImpl* audio_decoder = new AudioDecoderImpl(
       audio_parameters.audio_codec, audio_parameters.audio_header);
   if (!audio_decoder->is_valid()) {
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 9e0bbe4..b641fec 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
@@ -15,6 +15,7 @@
 #include "starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h"
 
 #include "starboard/log.h"
+#include "starboard/memory.h"
 #include "starboard/shared/starboard/application.h"
 #include "starboard/shared/starboard/drm/drm_system_internal.h"
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
@@ -71,6 +72,18 @@
       decode_target_provider_(provider)
 #endif  // SB_API_VERSION >= 4
 {
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  if (audio_header_.audio_specific_config_size > 0) {
+    audio_specific_config_.reset(
+        new int8_t[audio_header_.audio_specific_config_size]);
+    audio_header_.audio_specific_config = audio_specific_config_.get();
+    SbMemoryCopy(audio_specific_config_.get(),
+                 audio_header.audio_specific_config,
+                 audio_header.audio_specific_config_size);
+  }
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+
+  update_closure_ = Bind(&FilterBasedPlayerWorkerHandler::Update, this);
   bounds_ = PlayerWorker::Bounds();
 }
 
@@ -123,7 +136,6 @@
   ::starboard::ScopedLock lock(video_renderer_existence_mutex_);
   media_components->GetRenderers(&audio_renderer_, &video_renderer_);
 
-  update_closure_ = Bind(&FilterBasedPlayerWorkerHandler::Update, this);
   job_queue_->Schedule(update_closure_, kUpdateInterval);
 
   return true;
@@ -132,6 +144,10 @@
 bool FilterBasedPlayerWorkerHandler::Seek(SbMediaTime seek_to_pts, int ticket) {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
+  if (!audio_renderer_ || !video_renderer_) {
+    return false;
+  }
+
   if (seek_to_pts < 0) {
     SB_DLOG(ERROR) << "Try to seek to negative timestamp " << seek_to_pts;
     seek_to_pts = 0;
@@ -148,6 +164,10 @@
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
   SB_DCHECK(written != NULL);
 
+  if (!audio_renderer_ || !video_renderer_) {
+    return false;
+  }
+
   *written = true;
 
   if (input_buffer.sample_type() == kSbMediaTypeAudio) {
@@ -198,6 +218,10 @@
 bool FilterBasedPlayerWorkerHandler::WriteEndOfStream(SbMediaType sample_type) {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
+  if (!audio_renderer_ || !video_renderer_) {
+    return false;
+  }
+
   if (sample_type == kSbMediaTypeAudio) {
     if (audio_renderer_->IsEndOfStreamWritten()) {
       SB_LOG(WARNING) << "Try to write audio EOS after EOS is enqueued";
@@ -220,6 +244,10 @@
 bool FilterBasedPlayerWorkerHandler::SetPause(bool pause) {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
+  if (!audio_renderer_) {
+    return false;
+  }
+
   paused_ = pause;
 
   if (pause) {
@@ -237,6 +265,10 @@
 bool FilterBasedPlayerWorkerHandler::SetPlaybackRate(double playback_rate) {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
+  if (!audio_renderer_) {
+    return false;
+  }
+
   audio_renderer_->SetPlaybackRate(playback_rate);
   return true;
 }
@@ -260,6 +292,10 @@
 void FilterBasedPlayerWorkerHandler::Update() {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
 
+  if (!audio_renderer_ || !video_renderer_) {
+    return;
+  }
+
   if ((*player_worker_.*get_player_state_cb_)() == kSbPlayerStatePrerolling) {
     if (!audio_renderer_->IsSeekingInProgress() &&
         !video_renderer_->IsSeekingInProgress()) {
@@ -324,6 +360,7 @@
 #if SB_API_VERSION >= 4
 SbDecodeTarget FilterBasedPlayerWorkerHandler::GetCurrentDecodeTarget() {
   ::starboard::ScopedLock lock(video_renderer_existence_mutex_);
+
   if (video_renderer_) {
     return video_renderer_->GetCurrentDecodeTarget();
   } else {
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
index 3024054..610c4e1 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
@@ -85,6 +85,11 @@
   SbMediaVideoCodec video_codec_;
   SbMediaAudioCodec audio_codec_;
   SbDrmSystem drm_system_;
+#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
+  // Store a copy of |SbMediaAudioHeader::audio_specific_config| passed to the
+  // ctor so it is valid for the life time of the player worker.
+  scoped_array<int8_t> audio_specific_config_;
+#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
   SbMediaAudioHeader audio_header_;
 
   scoped_ptr<AudioRenderer> audio_renderer_;
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
index a5cddd7..8711274 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
@@ -41,7 +41,9 @@
 class StubAudioDecoder : public AudioDecoder {
  public:
   explicit StubAudioDecoder(const SbMediaAudioHeader& audio_header)
-      : sample_type_(GetSupportedSampleType()), audio_header_(audio_header) {}
+      : sample_type_(GetSupportedSampleType()),
+        audio_header_(audio_header),
+        stream_ended_(false) {}
   void Decode(const InputBuffer& input_buffer) SB_OVERRIDE {
     // Values to represent what kind of dummy audio to fill the decoded audio
     // we produce with.
@@ -86,6 +88,7 @@
                                             4 * last_input_buffer_.size()));
     }
     decoded_audios_.push(new DecodedAudio());
+    stream_ended_ = true;
   }
   scoped_refptr<DecodedAudio> Read() SB_OVERRIDE {
     scoped_refptr<DecodedAudio> result;
@@ -99,6 +102,7 @@
     while (!decoded_audios_.empty()) {
       decoded_audios_.pop();
     }
+    stream_ended_ = false;
     last_input_buffer_ = InputBuffer();
   }
   SbMediaAudioSampleType GetSampleType() const SB_OVERRIDE {
@@ -107,10 +111,16 @@
   int GetSamplesPerSecond() const SB_OVERRIDE {
     return audio_header_.samples_per_second;
   }
+  bool CanAcceptMoreData() const SB_OVERRIDE {
+    return !stream_ended_ && decoded_audios_.size() <= kMaxDecodedAudiosSize;
+  }
 
  private:
+  static const kMaxDecodedAudiosSize = 64;
+
   SbMediaAudioSampleType sample_type_;
   SbMediaAudioHeader audio_header_;
+  bool stream_ended_;
   std::queue<scoped_refptr<DecodedAudio> > decoded_audios_;
   InputBuffer last_input_buffer_;
 };
diff --git a/src/starboard/shared/stub/time_zone_get_dst_name.cc b/src/starboard/shared/stub/time_zone_get_dst_name.cc
index 0d4b0ba..9d96599 100644
--- a/src/starboard/shared/stub/time_zone_get_dst_name.cc
+++ b/src/starboard/shared/stub/time_zone_get_dst_name.cc
@@ -14,6 +14,8 @@
 
 #include "starboard/time_zone.h"
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 const char* SbTimeZoneGetDstName() {
   return "GMT";
 }
+#endif  // SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
diff --git a/src/starboard/shared/uwp/application_uwp.cc b/src/starboard/shared/uwp/application_uwp.cc
index 9af9928..41ed103 100644
--- a/src/starboard/shared/uwp/application_uwp.cc
+++ b/src/starboard/shared/uwp/application_uwp.cc
@@ -16,47 +16,134 @@
 
 #include "starboard/event.h"
 #include "starboard/log.h"
+#include "starboard/shared/starboard/application.h"
+#include "starboard/shared/uwp/window_internal.h"
+
+using starboard::shared::starboard::Application;
+using starboard::shared::starboard::CommandLine;
+using starboard::shared::uwp::ApplicationUwp;
+using Windows::ApplicationModel::Activation::IActivatedEventArgs;
+using Windows::ApplicationModel::Core::CoreApplication;
+using Windows::ApplicationModel::Core::CoreApplicationView;
+using Windows::ApplicationModel::Core::IFrameworkView;
+using Windows::ApplicationModel::Core::IFrameworkViewSource;
+using Windows::Foundation::TypedEventHandler;
+using Windows::UI::Core::CoreWindow;
+using Windows::UI::Core::CoreProcessEventsOption;
+
+ref class App sealed : public IFrameworkView {
+ public:
+  App() {}
+
+  // IFrameworkView methods.
+  virtual void Initialize(
+      Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) {
+    applicationView->Activated +=
+        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(
+            this, &App::OnActivated);
+  }
+  virtual void SetWindow(CoreWindow^ window) {}
+  virtual void Load(Platform::String^ entryPoint) {}
+  virtual void Run() {
+    CoreWindow ^window = CoreWindow::GetForCurrentThread();
+    window->Activate();
+    window->Dispatcher->ProcessEvents(
+        CoreProcessEventsOption::ProcessUntilQuit);
+  }
+  virtual void Uninitialize() {
+  }
+
+  void OnActivated(
+      CoreApplicationView^ applicationView, IActivatedEventArgs^ args) {
+    CoreWindow::GetForCurrentThread()->Activate();
+    ApplicationUwp::Get()->DispatchStart();
+  }
+};
+
+ref class Direct3DApplicationSource sealed : IFrameworkViewSource {
+ public:
+  Direct3DApplicationSource() {
+    SB_LOG(INFO) << "Direct3DApplicationSource";
+  }
+  virtual IFrameworkView^ CreateView() {
+    return ref new App();
+  }
+};
 
 namespace starboard {
 namespace shared {
 namespace uwp {
 
-ApplicationUwp::ApplicationUwp() {
-  SB_NOTIMPLEMENTED();
+ApplicationUwp::ApplicationUwp() : window_(kSbWindowInvalid) {}
+
+ApplicationUwp::~ApplicationUwp() {}
+
+void ApplicationUwp::Initialize() {}
+
+void ApplicationUwp::Teardown() {}
+
+Application::Event* ApplicationUwp::GetNextEvent() {
+  SB_NOTREACHED();
+  return nullptr;
 }
 
-ApplicationUwp::~ApplicationUwp() {
-  SB_NOTIMPLEMENTED();
+SbWindow ApplicationUwp::CreateWindow(const SbWindowOptions* options) {
+  // TODO: Determine why SB_DCHECK(IsCurrentThread()) fails in nplb, fix it,
+  // and add back this check.
+
+  if (SbWindowIsValid(window_)) {
+    return kSbWindowInvalid;
+  }
+
+  window_ = new SbWindowPrivate(options);
+  return window_;
 }
 
-void ApplicationUwp::Initialize() {
-  SB_NOTIMPLEMENTED();
+bool ApplicationUwp::DestroyWindow(SbWindow window) {
+  // TODO: Determine why SB_DCHECK(IsCurrentThread()) fails in nplb, fix it,
+  // and add back this check.
+
+  if (!SbWindowIsValid(window)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Invalid context.";
+    return false;
+  }
+
+  SB_DCHECK(window_ == window);
+  delete window;
+  window_ = kSbWindowInvalid;
+
+  return true;
 }
 
-void ApplicationUwp::Teardown() {
-  SB_NOTIMPLEMENTED();
-}
-
-bool ApplicationUwp::MayHaveSystemEvents() {
-  SB_NOTIMPLEMENTED();
+bool ApplicationUwp::DispatchNextEvent() {
+  auto direct3DApplicationSource = ref new Direct3DApplicationSource();
+  CoreApplication::Run(direct3DApplicationSource);
   return false;
 }
 
-shared::starboard::Application::Event* ApplicationUwp::PollNextSystemEvent() {
+void ApplicationUwp::Inject(Application::Event* event) {
+  // TODO: Implement with CoreWindow->GetForCurrentThread->Dispatcher->RunAsync
   SB_NOTIMPLEMENTED();
-  return NULL;
 }
 
-shared::starboard::Application::Event*
-ApplicationUwp::WaitForSystemEventWithTimeout(SbTime time) {
+void ApplicationUwp::InjectTimedEvent(Application::TimedEvent* timed_event) {
   SB_NOTIMPLEMENTED();
-  return NULL;
 }
 
-void ApplicationUwp::WakeSystemEventWait() {
+void ApplicationUwp::CancelTimedEvent(SbEventId event_id) {
   SB_NOTIMPLEMENTED();
 }
 
+Application::TimedEvent* ApplicationUwp::GetNextDueTimedEvent() {
+  SB_NOTIMPLEMENTED();
+  return nullptr;
+}
+
+SbTimeMonotonic ApplicationUwp::GetNextTimedEventTargetTime() {
+  SB_NOTIMPLEMENTED();
+  return 0;
+}
+
 }  // namespace uwp
 }  // namespace shared
 }  // namespace starboard
diff --git a/src/starboard/shared/uwp/application_uwp.h b/src/starboard/shared/uwp/application_uwp.h
index 437033a..f2c9efa 100644
--- a/src/starboard/shared/uwp/application_uwp.h
+++ b/src/starboard/shared/uwp/application_uwp.h
@@ -18,15 +18,28 @@
 #include "starboard/configuration.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/application.h"
-#include "starboard/shared/starboard/queue_application.h"
+#include "starboard/shared/starboard/command_line.h"
 #include "starboard/types.h"
+#include "starboard/window.h"
+
+namespace __winRT {
+// TODO: without this, we get the following error at CoreApplication::Run:
+// 'long __winRT::__getActivationFactoryByPCWSTR(i
+//  void *,Platform::Guid &,void **)':
+//  cannot convert argument 1 from 'const wchar_t [46]' to 'void *'
+inline long __getActivationFactoryByPCWSTR(const wchar_t* a,
+                                           Platform::Guid& b,
+                                           void** c) {
+  return __getActivationFactoryByPCWSTR(
+      static_cast<void*>(const_cast<wchar_t*>(a)), b, c);
+}
+}  // namespace __winRT
 
 namespace starboard {
 namespace shared {
 namespace uwp {
 
-// Stub application engine using the generic queue and a stub implementation.
-class ApplicationUwp : public shared::starboard::QueueApplication {
+class ApplicationUwp : public shared::starboard::Application {
  public:
   ApplicationUwp();
   ~ApplicationUwp() SB_OVERRIDE;
@@ -35,16 +48,32 @@
     return static_cast<ApplicationUwp*>(shared::starboard::Application::Get());
   }
 
- protected:
+// Do not use the macro from windows.h.
+#undef CreateWindow
+#undef CreateWindowW
+  SbWindow CreateWindow(const SbWindowOptions* options);
+
+  bool DestroyWindow(SbWindow window);
+
+  void DispatchStart() {
+    shared::starboard::Application::DispatchStart();
+  }
+
+ private:
   // --- Application overrides ---
+  bool IsStartImmediate() SB_OVERRIDE { return false; }
   void Initialize() SB_OVERRIDE;
   void Teardown() SB_OVERRIDE;
+  Event* GetNextEvent() SB_OVERRIDE;
+  bool DispatchNextEvent() SB_OVERRIDE;
+  void Inject(Event* event) SB_OVERRIDE;
+  void InjectTimedEvent(TimedEvent* timed_event) SB_OVERRIDE;
+  void CancelTimedEvent(SbEventId event_id) SB_OVERRIDE;
+  TimedEvent* GetNextDueTimedEvent() SB_OVERRIDE;
+  SbTimeMonotonic GetNextTimedEventTargetTime() SB_OVERRIDE;
 
-  // --- QueueApplication overrides ---
-  bool MayHaveSystemEvents() SB_OVERRIDE;
-  Event* PollNextSystemEvent() SB_OVERRIDE;
-  Event* WaitForSystemEventWithTimeout(SbTime time) SB_OVERRIDE;
-  void WakeSystemEventWait() SB_OVERRIDE;
+  // The single open window, if any.
+  SbWindow window_;
 };
 
 }  // namespace uwp
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/uwp/window_create.cc
similarity index 66%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/uwp/window_create.cc
index ba3f4ad..70ea0cc 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/uwp/window_create.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/window.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/uwp/application_uwp.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+SbWindow SbWindowCreate(const SbWindowOptions* options) {
+  return starboard::shared::uwp::ApplicationUwp::Get()->CreateWindow(options);
+}
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/uwp/window_destroy.cc
similarity index 68%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/uwp/window_destroy.cc
index ba3f4ad..34b7393 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/uwp/window_destroy.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/window.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/uwp/application_uwp.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+bool SbWindowDestroy(SbWindow window) {
+  return starboard::shared::uwp::ApplicationUwp::Get()->DestroyWindow(window);
+}
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/shared/uwp/window_get_platform_handle.cc
similarity index 70%
copy from src/starboard/raspi/1/atomic_public.h
copy to src/starboard/shared/uwp/window_get_platform_handle.cc
index 6fa6273..7e19456 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/shared/uwp/window_get_platform_handle.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#include "starboard/window.h"
 
-#include "starboard/raspi/shared/atomic_public.h"
+void* SbWindowGetPlatformHandle(SbWindow window) {
+  if (!SbWindowIsValid(window)) {
+    return NULL;
+  }
 
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+  return static_cast<void*>(window);
+}
diff --git a/src/starboard/shared/uwp/window_get_size.cc b/src/starboard/shared/uwp/window_get_size.cc
new file mode 100644
index 0000000..418a538
--- /dev/null
+++ b/src/starboard/shared/uwp/window_get_size.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 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/window.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/uwp/window_internal.h"
+
+bool SbWindowGetSize(SbWindow window, SbWindowSize* size) {
+  if (!SbWindowIsValid(window)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Invalid window.";
+    return false;
+  }
+
+  size->width = window->width;
+  size->height = window->height;
+  // The video resolution is the same as the graphics resolution.
+  size->video_pixel_ratio = 1.0f;
+  return true;
+}
diff --git a/src/starboard/shared/uwp/window_internal.cc b/src/starboard/shared/uwp/window_internal.cc
new file mode 100644
index 0000000..8fb0fc7
--- /dev/null
+++ b/src/starboard/shared/uwp/window_internal.cc
@@ -0,0 +1,22 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/uwp/window_internal.h"
+
+// TODO: Make sure the width and height here behave well given that we want
+// 1080 video, but perhaps 4k UI where applicable.
+SbWindowPrivate::SbWindowPrivate(const SbWindowOptions* /*options*/)
+    : width(1920), height(1080) {}
+
+SbWindowPrivate::~SbWindowPrivate() {}
diff --git a/src/starboard/shared/uwp/window_internal.h b/src/starboard/shared/uwp/window_internal.h
new file mode 100644
index 0000000..92d567b
--- /dev/null
+++ b/src/starboard/shared/uwp/window_internal.h
@@ -0,0 +1,61 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_UWP_WINDOW_INTERNAL_H_
+#define STARBOARD_SHARED_UWP_WINDOW_INTERNAL_H_
+
+#include "starboard/atomic.h"
+#include "starboard/time.h"
+#include "starboard/window.h"
+
+struct SbWindowPrivate {
+  explicit SbWindowPrivate(const SbWindowOptions* options);
+  ~SbWindowPrivate();
+
+  // Wait for the next video out vblank event.
+  void WaitForVBlank();
+
+  // Get the process time of the latest video out vblank event.
+  SbTime GetVBlankProcessTime();
+
+  // Get the video out refresh rate with the provided pointer. Return value
+  // indicates success.
+  bool GetRefreshRate(uint64_t* refresh_rate);
+
+  // The width of this window.
+  int width;
+
+  // The height of this window.
+  int height;
+
+  // The actual output resolution width.
+  int output_width;
+
+  // The actual output resolution height.
+  int output_height;
+
+ private:
+  // Open and Initialize the video output port.
+  void SetupVideo();
+
+  // Close the video output port.
+  void ShutdownVideo();
+
+  // TODO: Ensure this gets called when the output resolution may have changed,
+  // such as when resuming after suspend.
+  // Retrieve the width and height from the video output resolution.
+  void RefreshOutputResolution();
+};
+
+#endif  // STARBOARD_SHARED_UWP_WINDOW_INTERNAL_H_
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/shared/uwp/window_set_default_options.cc
similarity index 69%
copy from src/starboard/raspi/1/atomic_public.h
copy to src/starboard/shared/uwp/window_set_default_options.cc
index 6fa6273..e7d13c6 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/shared/uwp/window_set_default_options.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#include "starboard/window.h"
 
-#include "starboard/raspi/shared/atomic_public.h"
-
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+void SbWindowSetDefaultOptions(SbWindowOptions* /*options*/) {}
diff --git a/src/starboard/shared/win32/auto_event_handle.h b/src/starboard/shared/win32/auto_event_handle.h
new file mode 100644
index 0000000..24c3ccf
--- /dev/null
+++ b/src/starboard/shared/win32/auto_event_handle.h
@@ -0,0 +1,57 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_AUTO_EVENT_HANDLE_H_
+#define STARBOARD_SHARED_WIN32_AUTO_EVENT_HANDLE_H_
+
+#include <winsock2.h>
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+class AutoEventHandle {
+ public:
+  explicit AutoEventHandle(WSAEVENT event) : event_(event) {}
+
+  ~AutoEventHandle() { CleanupExistingEvent(); }
+
+  void Reset(WSAEVENT new_event) {
+    CleanupExistingEvent();
+    event_ = new_event;
+  }
+
+  bool IsValid() const { return event_ != WSA_INVALID_EVENT; }
+
+  WSAEVENT GetEvent() { return event_; }
+
+ private:
+  AutoEventHandle(const AutoEventHandle&) = delete;
+  AutoEventHandle& operator=(const AutoEventHandle&) = delete;
+
+  void CleanupExistingEvent() {
+    if (IsValid()) {
+      WSACloseEvent(event_);
+      event_ = WSA_INVALID_EVENT;
+    }
+  }
+
+  WSAEVENT event_;
+};
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_AUTO_EVENT_HANDLE_H_
diff --git a/src/starboard/shared/win32/error_utils.cc b/src/starboard/shared/win32/error_utils.cc
new file mode 100644
index 0000000..5a279ae
--- /dev/null
+++ b/src/starboard/shared/win32/error_utils.cc
@@ -0,0 +1,56 @@
+// Copyright 2017 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.
+
+// Not breaking these functions up because however one is implemented, the
+// others should be implemented similarly.
+
+#include "starboard/shared/win32/error_utils.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+std::ostream& operator<<(std::ostream& os, const Win32ErrorCode& error_code) {
+  LPWSTR error_message;
+  int message_size = FormatMessage(
+      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+      nullptr,  // Unused with FORMAT_MESSAGE_FROM_SYSTEM.
+      error_code.GetHRESULT(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+      (LPTSTR)&error_message,
+      0,  // Minimum size for output buffer.
+      nullptr);
+  SB_DCHECK(message_size);
+  os << wchar_tToUTF8(error_message);
+  LocalFree(error_message);
+
+  return os;
+}
+
+void DebugLogWinError() {
+#if defined(_DEBUG)
+  DWORD error_code = GetLastError();
+  if (!error_code)
+    return;
+
+  SB_LOG(ERROR) << Win32ErrorCode(error_code);
+#endif  // defined(_DEBUG)
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/win32/error_utils.h b/src/starboard/shared/win32/error_utils.h
new file mode 100644
index 0000000..2a7dcfb
--- /dev/null
+++ b/src/starboard/shared/win32/error_utils.h
@@ -0,0 +1,49 @@
+// Copyright 2017 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.
+
+// Not breaking these functions up because however one is implemented, the
+// others should be implemented similarly.
+
+#ifndef STARBOARD_SHARED_WIN32_ERROR_UTILS_H_
+#define STARBOARD_SHARED_WIN32_ERROR_UTILS_H_
+
+#include <windows.h>
+
+#include <iostream>
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+class Win32ErrorCode {
+ public:
+  explicit Win32ErrorCode(DWORD error_code) : error_code_(error_code) {}
+
+  HRESULT GetHRESULT() const { return HRESULT_FROM_WIN32(error_code_); }
+
+ private:
+  DWORD error_code_;
+};
+
+std::ostream& operator<<(std::ostream& os, const Win32ErrorCode& error_code);
+
+// Checks for system errors and logs a human-readable error if GetLastError()
+// returns an error code. Noops on non-debug builds.
+void DebugLogWinError();
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_ERROR_UTILS_H_
diff --git a/src/starboard/shared/win32/socket_get_interface_address.cc b/src/starboard/shared/win32/socket_get_interface_address.cc
index 7b4118a..22e2bb9 100644
--- a/src/starboard/shared/win32/socket_get_interface_address.cc
+++ b/src/starboard/shared/win32/socket_get_interface_address.cc
@@ -333,10 +333,8 @@
                             out_netmask));
   } else if (IsAnyAddress(*destination)) {
     return FindInterfaceIP(destination->type, out_source_address, out_netmask);
-  } else {
-    return (FindSourceAddressForDestination(*destination, out_source_address) &&
-            GetNetmaskForInterfaceAddress(*out_source_address, out_netmask));
   }
 
-  return false;
+  return (FindSourceAddressForDestination(*destination, out_source_address) &&
+          GetNetmaskForInterfaceAddress(*out_source_address, out_netmask));
 }
diff --git a/src/starboard/shared/win32/socket_internal.cc b/src/starboard/shared/win32/socket_internal.cc
index c81df3e..d61dc1b 100644
--- a/src/starboard/shared/win32/socket_internal.cc
+++ b/src/starboard/shared/win32/socket_internal.cc
@@ -104,7 +104,7 @@
       length = kAddressStructLengthIpv4;
       SbMemorySet(addr, 0, length);
       addr->sin_family = AF_INET;
-      addr->sin_port = htons(address->port);
+      addr->sin_port = htons(static_cast<USHORT>(address->port));
       SbMemoryCopy(&addr->sin_addr, address->address, kAddressLengthIpv4);
       break;
     }
@@ -113,7 +113,7 @@
       length = kAddressStructLengthIpv6;
       SbMemorySet(addr6, 0, length);
       addr6->sin6_family = AF_INET6;
-      addr6->sin6_port = htons(address->port);
+      addr6->sin6_port = htons(static_cast<USHORT>(address->port));
       SbMemoryCopy(&addr6->sin6_addr, address->address, kAddressLengthIpv6);
       break;
     }
diff --git a/src/starboard/shared/win32/socket_internal.h b/src/starboard/shared/win32/socket_internal.h
index ce32fcf..fa29128 100644
--- a/src/starboard/shared/win32/socket_internal.h
+++ b/src/starboard/shared/win32/socket_internal.h
@@ -19,10 +19,13 @@
 #include <WS2tcpip.h>
 
 #include "starboard/shared/internal_only.h"
+#include "starboard/shared/win32/auto_event_handle.h"
 #include "starboard/socket.h"
 #include "starboard/socket_waiter.h"
 #include "starboard/types.h"
 
+namespace sbwin32 = starboard::shared::win32;
+
 struct SbSocketPrivate {
   enum struct BindTarget {
     kUnbound = 0,
@@ -38,6 +41,7 @@
       : address_type(address_type),
         protocol(protocol),
         socket_handle(handle),
+        socket_event(WSA_INVALID_EVENT),
         error(kSbSocketOk),
         waiter(kSbSocketWaiterInvalid),
         bound_to(bound_to) {}
@@ -49,9 +53,12 @@
   // The protocol of this socket, UDP or TCP.
   SbSocketProtocol protocol;
 
-  // The file descriptor for this socket.
+  // The handle for this socket.
   SOCKET socket_handle;
 
+  // The event related to the socket_handle.  Used for SbSocketWaiter.
+  sbwin32::AutoEventHandle socket_event;
+
   // The last error that occurred on this socket, or kSbSocketOk.
   SbSocketError error;
 
diff --git a/src/starboard/shared/win32/socket_waiter_add.cc b/src/starboard/shared/win32/socket_waiter_add.cc
new file mode 100644
index 0000000..3b5d9dc
--- /dev/null
+++ b/src/starboard/shared/win32/socket_waiter_add.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 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/socket_waiter.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
+
+bool SbSocketWaiterAdd(SbSocketWaiter waiter,
+                       SbSocket socket,
+                       void* context,
+                       SbSocketWaiterCallback callback,
+                       int interests,
+                       bool persistent) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Waiter (" << waiter << ") is invalid.";
+    return false;
+  }
+
+  if (!SbSocketIsValid(socket)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid.";
+    return false;
+  }
+
+  if (!callback) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": No callback provided.";
+    return false;
+  }
+
+  if (!interests) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided.";
+    return false;
+  }
+
+  return waiter->Add(socket, context, callback, interests, persistent);
+}
diff --git a/src/starboard/raspi/1/atomic_public.h b/src/starboard/shared/win32/socket_waiter_create.cc
similarity index 70%
copy from src/starboard/raspi/1/atomic_public.h
copy to src/starboard/shared/win32/socket_waiter_create.cc
index 6fa6273..05e8cd0 100644
--- a/src/starboard/raspi/1/atomic_public.h
+++ b/src/starboard/shared/win32/socket_waiter_create.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
-#define STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+#include "starboard/socket_waiter.h"
 
-#include "starboard/raspi/shared/atomic_public.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
 
-#endif  // STARBOARD_RASPI_1_ATOMIC_PUBLIC_H_
+SbSocketWaiter SbSocketWaiterCreate() {
+  return new SbSocketWaiterPrivate();
+}
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/win32/socket_waiter_destroy.cc
similarity index 65%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/win32/socket_waiter_destroy.cc
index ba3f4ad..69b38e1 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/win32/socket_waiter_destroy.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/socket_waiter.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+bool SbSocketWaiterDestroy(SbSocketWaiter waiter) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    return false;
+  }
+  delete waiter;
+  return true;
+}
diff --git a/src/starboard/shared/win32/socket_waiter_internal.cc b/src/starboard/shared/win32/socket_waiter_internal.cc
new file mode 100644
index 0000000..2d10a70
--- /dev/null
+++ b/src/starboard/shared/win32/socket_waiter_internal.cc
@@ -0,0 +1,457 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/win32/socket_waiter_internal.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/error_utils.h"
+#include "starboard/shared/win32/socket_internal.h"
+#include "starboard/shared/win32/thread_private.h"
+#include "starboard/shared/win32/time_utils.h"
+#include "starboard/thread.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+namespace {
+
+// This is a helper function that takes data from |network_events|, and then
+// adds the bitwise ORs |interest_to_add| onto |interest_out|.
+// For more information, please see
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms741572(v=vs.85).aspx.
+void TranslateNetworkBitIntoInterests(const WSANETWORKEVENTS& network_events,
+                                      int bit_to_check,
+                                      SbSocketWaiterInterest interest_to_add,
+                                      SbSocketWaiterInterest* interests_out) {
+  SB_DCHECK(interests_out);
+
+  static_assert(
+      sizeof(SbSocketWaiterInterest) == sizeof(int),
+      "Assuming size of enum is size of int, due to the bitfield logic below.");
+
+  if (network_events.lNetworkEvents & (1 << bit_to_check)) {
+    *(reinterpret_cast<int*>(interests_out)) |=
+        static_cast<int>(interest_to_add);
+    const int error_code = network_events.iErrorCode[bit_to_check];
+    if (error_code != 0) {
+      SB_DLOG(ERROR) << "Error on network event " << bit_to_check << " "
+                     << sbwin32::Win32ErrorCode(error_code);
+    }
+  }
+}
+
+SbSocketWaiterInterest DiscoverNetworkEventInterests(SOCKET socket_handle) {
+  // Please take note that WSAEnumNetworkEvents below only works with
+  // WSAEventSelect.
+  SbSocketWaiterInterest interests = kSbSocketWaiterInterestNone;
+  WSANETWORKEVENTS network_events = {0};
+  int return_code =
+      WSAEnumNetworkEvents(socket_handle, nullptr, &network_events);
+  if (return_code == SOCKET_ERROR) {
+    int last_error = WSAGetLastError();
+    SB_DLOG(ERROR) << "WSAEnumNetworkEvents failed with last_error = "
+                   << sbwin32::Win32ErrorCode(last_error);
+    return interests;
+  }
+
+  // Translate information from WSAEnumNetworkEvents to interests:
+  // From the MSDN documentation:
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms741572(v=vs.85).aspx
+  // The lNetworkEvents member of the WSANETWORKEVENTS structure indicates which
+  // of the FD_XXX network events have occurred. The iErrorCode array is used to
+  // contain any associated error codes with the array index corresponding to
+  // the position of event bits in lNetworkEvents. Identifiers such as
+  // FD_READ_BIT and FD_WRITE_BIT can be used to index the iErrorCode array.
+  // Note that only those elements of the iErrorCode array are set that
+  // correspond to the bits set in lNetworkEvents parameter
+  TranslateNetworkBitIntoInterests(network_events, FD_READ_BIT,
+                                   kSbSocketWaiterInterestRead, &interests);
+  TranslateNetworkBitIntoInterests(network_events, FD_ACCEPT_BIT,
+                                   kSbSocketWaiterInterestRead, &interests);
+  TranslateNetworkBitIntoInterests(network_events, FD_CLOSE_BIT,
+                                   kSbSocketWaiterInterestRead, &interests);
+
+  TranslateNetworkBitIntoInterests(network_events, FD_CONNECT_BIT,
+                                   kSbSocketWaiterInterestWrite, &interests);
+  TranslateNetworkBitIntoInterests(network_events, FD_WRITE_BIT,
+                                   kSbSocketWaiterInterestWrite, &interests);
+
+  return interests;
+}
+
+// The function erases the |index|th element from the collection by swapping
+// it with the last element.  This operation leaves all the other elements in
+// place, which is useful for some operations.
+template <typename T>
+void EraseIndexFromVector(T* collection_pointer, std::size_t index) {
+  SB_DCHECK(collection_pointer);
+  T& collection = *collection_pointer;
+  const std::size_t current_size = collection.size();
+  if (current_size <= 1) {
+    collection.clear();
+    return;
+  }
+  const std::size_t new_size = collection.size() - 1;
+  std::swap(collection[index], collection[new_size]);
+  collection.resize(new_size);
+}
+
+}  // namespace
+
+SbSocketWaiterPrivate::SbSocketWaiterPrivate()
+    : thread_(SbThreadGetCurrent()),
+      wakeup_event_token_(-1),
+      wakeup_event_(CreateEvent(nullptr, false, false, nullptr)) {
+  {
+    starboard::ScopedLock lock(unhandled_wakeup_count_mutex_);
+    unhandled_wakeup_count_ = 0;
+  }
+  if (wakeup_event_.IsValid() == false) {
+    SB_DLOG(ERROR) << "Could not create wakeup event: "
+                   << starboard::shared::win32::Win32ErrorCode(GetLastError());
+    return;
+  }
+  wakeup_event_token_ =
+      waitees_.AddSocketEventAndWaitee(wakeup_event_.GetEvent(), nullptr);
+}
+
+SbSocketWaiterPrivate::~SbSocketWaiterPrivate() {
+  for (auto& it : waitees_.GetWaitees()) {
+    if (it) {
+      SB_DCHECK(CheckSocketWaiterIsThis(it->socket));
+    }
+  }
+}
+
+bool SbSocketWaiterPrivate::Add(SbSocket socket,
+                                void* context,
+                                SbSocketWaiterCallback callback,
+                                int interests,
+                                bool persistent) {
+  SB_DCHECK(SbThreadIsCurrent(thread_));
+
+  if (!SbSocketIsValid(socket)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid.";
+    return false;
+  }
+
+  if (!interests) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided.";
+    return false;
+  }
+
+  // The policy is not to add a socket to a waiter if it is registered with
+  // another waiter.
+
+  // TODO: If anyone were to want to add a socket to a different waiter,
+  // it would probably be another thread, so doing this check without locking is
+  // probably wrong. But, it is also a pain, and, at this precise moment, socket
+  // access is all going to come from one I/O thread anyway, and there will only
+  // be one waiter.
+  if (SbSocketWaiterIsValid(socket->waiter)) {
+    if (socket->waiter == this) {
+      SB_DLOG(ERROR) << __FUNCTION__ << ": Socket already has this waiter ("
+                     << this << ").";
+    } else {
+      SB_DLOG(ERROR) << __FUNCTION__ << ": Socket already has waiter ("
+                     << socket->waiter << ", this=" << this << ").";
+    }
+    return false;
+  }
+
+  long network_event_interests = 0;
+  if (interests & kSbSocketWaiterInterestRead) {
+    network_event_interests |= FD_READ | FD_ACCEPT | FD_CLOSE;
+  }
+
+  if (interests & kSbSocketWaiterInterestWrite) {
+    network_event_interests |= FD_CONNECT | FD_WRITE;
+  }
+
+  const BOOL manual_reset = !persistent;
+
+  SB_DCHECK(!socket->socket_event.IsValid());
+
+  socket->socket_event.Reset(
+      CreateEvent(nullptr, manual_reset, false, nullptr));
+  if (socket->socket_event.GetEvent() == WSA_INVALID_EVENT) {
+    int last_error = WSAGetLastError();
+    SB_DLOG(ERROR) << "Error calling WSACreateEvent() last_error = "
+                   << sbwin32::Win32ErrorCode(last_error);
+    return false;
+  }
+
+  // Note that WSAEnumNetworkEvents used elsewhere only works with
+  // WSAEventSelect.
+  // Please consider that before changing this code.
+  int return_value =
+      WSAEventSelect(socket->socket_handle, socket->socket_event.GetEvent(),
+                     network_event_interests);
+
+  if (return_value == SOCKET_ERROR) {
+    int last_error = WSAGetLastError();
+    SB_DLOG(ERROR) << "Error calling WSAEventSelect() last_error = "
+                   << sbwin32::Win32ErrorCode(last_error);
+    return false;
+  }
+
+  if (waitees_.GetHandleArraySize() >= MAXIMUM_WAIT_OBJECTS) {
+    SB_DLOG(ERROR) << "Reached maxed number of socket events ("
+                   << MAXIMUM_WAIT_OBJECTS << ")";
+    return false;
+  }
+
+  std::unique_ptr<Waitee> waitee(
+      new Waitee(this, socket, context, callback, interests, persistent));
+  waitees_.AddSocketEventAndWaitee(socket->socket_event.GetEvent(),
+                                   std::move(waitee));
+  socket->waiter = this;
+
+  return true;
+}
+
+bool SbSocketWaiterPrivate::Remove(SbSocket socket) {
+  SB_DCHECK(SbThreadIsCurrent(thread_));
+
+  if (!CheckSocketWaiterIsThis(socket)) {
+    return false;
+  }
+
+  socket->waiter = kSbSocketWaiterInvalid;
+
+  socket->socket_event.Reset(nullptr);
+  return waitees_.RemoveSocket(socket);
+}
+
+void SbSocketWaiterPrivate::HandleWakeUpRead() {
+  SB_LOG(INFO) << "HandleWakeUpRead incrementing counter..";
+  starboard::ScopedLock lock(unhandled_wakeup_count_mutex_);
+  ++unhandled_wakeup_count_;
+}
+
+void SbSocketWaiterPrivate::SignalWakeupEvent() {
+  SB_DCHECK(wakeup_event_.IsValid());
+  WSASetEvent(wakeup_event_.GetEvent());
+}
+
+void SbSocketWaiterPrivate::ResetWakeupEvent() {
+  SB_DCHECK(wakeup_event_.IsValid());
+  WSAResetEvent(wakeup_event_.GetEvent());
+}
+
+bool SbSocketWaiterPrivate::CheckSocketWaiterIsThis(SbSocket socket) {
+  if (!SbSocketIsValid(socket)) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid.";
+    return false;
+  }
+
+  if (socket->waiter != this) {
+    SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") "
+                   << "is watched by Waiter (" << socket->waiter << "), "
+                   << "not this Waiter (" << this << ").";
+    SB_DSTACK(ERROR);
+    return false;
+  }
+
+  return true;
+}
+
+void SbSocketWaiterPrivate::Wait() {
+  SB_DCHECK(SbThreadIsCurrent(thread_));
+
+  // We basically wait for the largest amount of time to achieve an indefinite
+  // block.
+  WaitTimed(kSbTimeMax);
+}
+
+SbSocketWaiterResult SbSocketWaiterPrivate::WaitTimed(SbTime duration) {
+  SB_DCHECK(SbThreadIsCurrent(thread_));
+
+  const SbTimeMonotonic start_time = SbTimeGetMonotonicNow();
+  int64_t duration_left = duration;
+  SbSocketWaiterResult result = kSbSocketWaiterResultInvalid;
+
+  while (true) {
+    // |waitees_| could have been modified in the last loop iteration, so
+    // re-read it.
+    const DWORD number_events =
+        static_cast<DWORD>(waitees_.GetHandleArraySize());
+
+    const DWORD millis = sbwin32::ConvertSbTimeToMillisRoundUp(duration_left);
+
+    bool woke_up = false;
+    {
+      starboard::ScopedLock lock(unhandled_wakeup_count_mutex_);
+      if (unhandled_wakeup_count_ > 0) {
+        --unhandled_wakeup_count_;
+        woke_up = true;
+      }
+    }
+
+    if (woke_up) {
+      // The signaling thread also set the event, so reset it.
+      ResetWakeupEvent();
+      return kSbSocketWaiterResultWokenUp;
+    }
+
+    // There should always be a wakeup event.
+    SB_DCHECK(number_events > 0);
+
+    DWORD return_value = WSAWaitForMultipleEvents(
+        number_events, waitees_.GetHandleArray(), false, millis, false);
+
+    if ((return_value >= WSA_WAIT_EVENT_0) &&
+        (return_value < (WSA_WAIT_EVENT_0 + number_events))) {
+      int64_t socket_index = static_cast<int64_t>(return_value) -
+                             static_cast<int64_t>(WSA_WAIT_EVENT_0);
+      SB_DCHECK(socket_index >= 0);
+      if (socket_index < 0) {
+        SB_NOTREACHED() << "Bad socket_index. " << socket_index;
+        return kSbSocketWaiterResultTimedOut;
+      }
+
+      // Make sure wakeup_event_token_ is initialized.
+      SB_DCHECK(wakeup_event_token_ >= 0);
+
+      if (socket_index == wakeup_event_token_) {
+        {
+          starboard::ScopedLock lock(unhandled_wakeup_count_mutex_);
+          SB_DCHECK(unhandled_wakeup_count_ > 0);
+
+          if (unhandled_wakeup_count_ > 0) {
+            --unhandled_wakeup_count_;
+            // This was a dummy event.  We were woken up.
+            // Note that we do not need to reset the event here,
+            // since it was created using an auto-reset flag.
+            return kSbSocketWaiterResultWokenUp;
+          }
+        }
+
+        ResetWakeupEvent();
+      } else {
+        Waitee* waitee = waitees_.GetWaiteeByIndex(socket_index);
+
+        // Remove the non-persistent waitee before calling the callback, so
+        // that we can add another waitee in the callback if we need to. This
+        // is also why we copy all the fields we need out of waitee.
+        const SbSocket socket = waitee->socket;
+        const SbSocketWaiterCallback callback = waitee->callback;
+        void* context = waitee->context;
+
+        // Note: this should also go before Remove().
+        const SbSocketWaiterInterest interests =
+            DiscoverNetworkEventInterests(socket->socket_handle);
+
+        if (!waitee->persistent) {
+          Remove(waitee->socket);
+        }
+
+        callback(this, socket, context, interests);
+      }
+    } else if (return_value == WSA_WAIT_FAILED) {
+      SB_DLOG(ERROR) << "Wait failed -- "
+                     << sbwin32::Win32ErrorCode(WSAGetLastError());
+      return kSbSocketWaiterResultInvalid;
+    } else if (return_value == WSA_WAIT_TIMEOUT) {
+      // Do nothing, check time ourselves.
+    } else {
+      SB_NOTREACHED() << "Unhandled case: " << return_value;
+      return kSbSocketWaiterResultInvalid;
+    }
+
+    const int64_t time_elapsed =
+        static_cast<std::int64_t>(SbTimeGetMonotonicNow()) -
+        static_cast<std::int64_t>(start_time);
+    duration_left -= time_elapsed;
+    if (duration_left < 0) {
+      return kSbSocketWaiterResultTimedOut;
+    }
+  }
+
+  SB_NOTREACHED() << "Invalid state reached";
+  return kSbSocketWaiterResultInvalid;
+}
+
+void SbSocketWaiterPrivate::WakeUp() {
+  {
+    starboard::ScopedLock lock(unhandled_wakeup_count_mutex_);
+    ++unhandled_wakeup_count_;
+  }
+  SignalWakeupEvent();
+}
+
+SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::WaiteeRegistry::GetWaitee(
+    SbSocket socket) {
+  auto iterator = socket_to_index_map_.find(socket);
+  if (iterator == socket_to_index_map_.end()) {
+    return nullptr;
+  }
+  return waitees_[iterator->second].get();
+}
+
+SbSocketWaiterPrivate::WaiteeRegistry::LookupToken
+SbSocketWaiterPrivate::WaiteeRegistry::AddSocketEventAndWaitee(
+    WSAEVENT socket_event,
+    std::unique_ptr<Waitee> waitee) {
+  SB_DCHECK(socket_event != WSA_INVALID_EVENT);
+  SB_DCHECK(socket_events_.size() == waitees_.size());
+  SbSocket socket = kSbSocketInvalid;
+  if (waitee) {
+    socket = waitee->socket;
+  }
+  socket_to_index_map_.emplace(socket, socket_events_.size());
+  socket_events_.emplace_back(socket_event);
+  waitees_.emplace_back(std::move(waitee));
+
+  return socket_events_.size() - 1;
+}
+
+bool SbSocketWaiterPrivate::WaiteeRegistry::RemoveSocket(SbSocket socket) {
+  auto iterator = socket_to_index_map_.find(socket);
+  if (iterator == socket_to_index_map_.end()) {
+    return false;
+  }
+
+  const std::size_t current_size = socket_events_.size();
+  SB_DCHECK(current_size == waitees_.size());
+
+  const std::size_t socket_index = iterator->second;
+  SbSocket socket_to_swap = waitees_[current_size - 1]->socket;
+
+  // Since |EraseIndexFromVector| will swap the last socket and the socket
+  // at current index, |socket_to_index_| will need to be updated.
+  socket_to_index_map_[socket_to_swap] = socket_index;
+  // Note that |EraseIndexFromVector| only touches the last element and the
+  // element to remove.
+  EraseIndexFromVector(&socket_events_, socket_index);
+  EraseIndexFromVector(&waitees_, socket_index);
+
+  socket_to_index_map_.erase(socket);
+
+  SB_DCHECK(socket_events_.size() == waitees_.size());
+  SB_DCHECK(socket_events_.size() == socket_to_index_map_.size());
+  return true;
+}
+
+SbSocketWaiterPrivate::Waitee*
+SbSocketWaiterPrivate::WaiteeRegistry::GetWaiteeByIndex(
+    const SbSocketWaiterPrivate::WaiteeRegistry::LookupToken socket_index) {
+  SB_DCHECK(socket_index >= 0);
+
+  SB_DCHECK(static_cast<std::size_t>(socket_index) <= socket_events_.size());
+  return waitees_[socket_index].get();
+}
diff --git a/src/starboard/shared/win32/socket_waiter_internal.h b/src/starboard/shared/win32/socket_waiter_internal.h
new file mode 100644
index 0000000..193361b
--- /dev/null
+++ b/src/starboard/shared/win32/socket_waiter_internal.h
@@ -0,0 +1,144 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_SOCKET_WAITER_INTERNAL_H_
+#define STARBOARD_SHARED_WIN32_SOCKET_WAITER_INTERNAL_H_
+
+#include <windows.h>
+#include <winsock2.h>
+
+#include <deque>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "starboard/mutex.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/win32/auto_event_handle.h"
+#include "starboard/shared/win32/socket_internal.h"
+#include "starboard/socket.h"
+#include "starboard/socket_waiter.h"
+#include "starboard/thread.h"
+#include "starboard/types.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+#pragma warning(push)
+
+// SbSocketWaiterPrivate is defined as a struct, but for windows implementation
+// enough functionality has been added so that it warrants being a class
+// per Google's C++ style guide.  This mismatch causes the Microsoft's compiler
+// to generate a warning.
+#pragma warning(disable : 4099)
+class SbSocketWaiterPrivate {
+ public:
+  SbSocketWaiterPrivate();
+  ~SbSocketWaiterPrivate();
+
+  // These methods implement the SbSocketWaiter API defined in socket_waiter.h.
+  bool Add(SbSocket socket,
+           void* context,
+           SbSocketWaiterCallback callback,
+           int interests,
+           bool persistent);
+  bool Remove(SbSocket socket);
+  void Wait();
+  SbSocketWaiterResult WaitTimed(SbTime duration);
+  void WakeUp();
+  void HandleWakeUpRead();
+
+ private:
+  // A registration of a socket with a socket waiter.
+  struct Waitee {
+    Waitee(SbSocketWaiter waiter,
+           SbSocket socket,
+           void* context,
+           SbSocketWaiterCallback callback,
+           int interests,
+           bool persistent)
+        : waiter(waiter),
+          socket(socket),
+          context(context),
+          callback(callback),
+          interests(interests),
+          persistent(persistent) {}
+    // The waiter this event is registered with.
+    SbSocketWaiter waiter;
+
+    // The socket registered with the waiter.
+    SbSocket socket;
+
+    // A context value that will be passed to the callback.
+    void* context;
+
+    // The callback to call when one or more registered interests become ready.
+    SbSocketWaiterCallback callback;
+
+    // The set of interests registered with the waiter.
+    int interests;
+
+    // Whether this Waitee should stay registered after the next callback.
+    bool persistent;
+  };
+
+  class WaiteeRegistry {
+   public:
+    typedef int64_t LookupToken;
+    typedef std::deque<std::unique_ptr<Waitee>> Waitees;
+    typedef std::unordered_map<SbSocket, std::size_t> SocketToIndex;
+
+    WSAEVENT* GetHandleArray() { return socket_events_.data(); }
+    std::size_t GetHandleArraySize() { return socket_events_.size(); }
+    const Waitees& GetWaitees() const { return waitees_; }
+
+    // Gets the Waitee associated with the given socket, or nullptr.
+    Waitee* GetWaitee(SbSocket socket);
+    // Gets the Waitee by index.
+    Waitee* GetWaiteeByIndex(LookupToken socket_index);
+
+    // Returns the index of the event.
+    LookupToken AddSocketEventAndWaitee(WSAEVENT socket_event,
+                                        std::unique_ptr<Waitee> waitee);
+    // Returns true if socket was found, and removed.
+    bool RemoveSocket(SbSocket socket);
+
+   private:
+    SocketToIndex socket_to_index_map_;
+    std::vector<WSAEVENT> socket_events_;
+    std::deque<std::unique_ptr<Waitee>> waitees_;
+  };
+
+  void SignalWakeupEvent();
+  void ResetWakeupEvent();
+
+  bool CheckSocketWaiterIsThis(SbSocket socket);
+
+  // The thread this waiter was created on. Immutable, so accessible from any
+  // thread.
+  const SbThread thread_;
+
+  // The registry of currently registered Waitees.
+  WaiteeRegistry waitees_;
+  WaiteeRegistry::LookupToken wakeup_event_token_;
+
+  // Number of times wake up has been called, and not handled.
+  starboard::Mutex unhandled_wakeup_count_mutex_;
+  std::int32_t unhandled_wakeup_count_;
+
+  // The WSAEvent that is set by Wakeup();
+  sbwin32::AutoEventHandle wakeup_event_;
+};
+#pragma warning(pop)
+
+#endif  // STARBOARD_SHARED_WIN32_SOCKET_WAITER_INTERNAL_H_
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/win32/socket_waiter_remove.cc
similarity index 63%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/win32/socket_waiter_remove.cc
index ba3f4ad..0f9a96c 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/win32/socket_waiter_remove.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/socket_waiter.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    return false;
+  }
+
+  return waiter->Remove(socket);
+}
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/win32/socket_waiter_wait.cc
similarity index 66%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/win32/socket_waiter_wait.cc
index ba3f4ad..798b6d1 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/win32/socket_waiter_wait.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/socket_waiter.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+void SbSocketWaiterWait(SbSocketWaiter waiter) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    return;
+  }
+
+  waiter->Wait();
+}
diff --git a/src/starboard/shared/win32/socket_waiter_wait_timed.cc b/src/starboard/shared/win32/socket_waiter_wait_timed.cc
new file mode 100644
index 0000000..6823218
--- /dev/null
+++ b/src/starboard/shared/win32/socket_waiter_wait_timed.cc
@@ -0,0 +1,26 @@
+// Copyright 2017 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/socket_waiter.h"
+
+#include "starboard/shared/win32/socket_waiter_internal.h"
+
+SbSocketWaiterResult SbSocketWaiterWaitTimed(SbSocketWaiter waiter,
+                                             SbTime duration) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    return kSbSocketWaiterResultInvalid;
+  }
+
+  return waiter->WaitTimed(duration);
+}
diff --git a/src/starboard/raspi/1/thread_types_public.h b/src/starboard/shared/win32/socket_waiter_wake_up.cc
similarity index 66%
copy from src/starboard/raspi/1/thread_types_public.h
copy to src/starboard/shared/win32/socket_waiter_wake_up.cc
index ba3f4ad..9583560 100644
--- a/src/starboard/raspi/1/thread_types_public.h
+++ b/src/starboard/shared/win32/socket_waiter_wake_up.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright 2017 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.
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+#include "starboard/socket_waiter.h"
 
-#include "starboard/raspi/shared/thread_types_public.h"
+#include "starboard/shared/win32/socket_waiter_internal.h"
 
-#endif  // STARBOARD_RASPI_1_THREAD_TYPES_PUBLIC_H_
+void SbSocketWaiterWakeUp(SbSocketWaiter waiter) {
+  if (!SbSocketWaiterIsValid(waiter)) {
+    return;
+  }
+
+  waiter->WakeUp();
+}
diff --git a/src/starboard/shared/win32/system_break_into_debugger.cc b/src/starboard/shared/win32/system_break_into_debugger.cc
index 121d052..45c9158 100644
--- a/src/starboard/shared/win32/system_break_into_debugger.cc
+++ b/src/starboard/shared/win32/system_break_into_debugger.cc
@@ -14,10 +14,11 @@
 
 #include "starboard/system.h"
 
-#include <windows.h>
+#include <intrin.h>
 
 void SbSystemBreakIntoDebugger() {
-  // TODO: neither of these may be valid on some platforms.
-  DebugBreak();
-  ExitProcess(1);
+  // Note: neither DebugBreak() nor ExitProcess() are valid
+  // on some Windows platforms (eg UWP) so we use __debugbreak()
+  // instead.
+  __debugbreak();
 }
diff --git a/src/starboard/shared/win32/system_get_random_data.cc b/src/starboard/shared/win32/system_get_random_data.cc
new file mode 100644
index 0000000..a34f696
--- /dev/null
+++ b/src/starboard/shared/win32/system_get_random_data.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 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/system.h"
+
+#include <windows.h>
+
+// This must be included after windows.h
+#include <bcrypt.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/error_utils.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+void SbSystemGetRandomData(void* out_buffer, int buffer_size) {
+  // Note: this might not be secure before Windows 10, as
+  // BCRYPT_RNG_DUAL_EC_ALGORITHM might be used.  See:
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375534%28v=vs.85%29.aspx
+  // "Windows 10:  Beginning with Windows 10, the dual elliptic curve random
+  // number generator algorithm has been removed. Existing uses of this
+  // algorithm will continue to work; however, the random number generator is
+  // based on the AES counter mode specified in the NIST SP 800-90 standard. New
+  // code should use BCRYPT_RNG_ALGORITHM, and it is recommended that existing
+  // code be changed to use BCRYPT_RNG_ALGORITHM."
+  NTSTATUS status =
+      BCryptGenRandom(nullptr, reinterpret_cast<PUCHAR>(out_buffer),
+                      buffer_size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+  SB_DCHECK(status == 0) << "Error while calling CryptGenRandom: "
+                         << sbwin32::Win32ErrorCode(GetLastError());
+}
diff --git a/src/starboard/shared/win32/system_get_random_uint64.cc b/src/starboard/shared/win32/system_get_random_uint64.cc
index 632c39d..2eb95f7 100644
--- a/src/starboard/shared/win32/system_get_random_uint64.cc
+++ b/src/starboard/shared/win32/system_get_random_uint64.cc
@@ -14,17 +14,8 @@
 
 #include "starboard/system.h"
 
-#include <windows.h>
-
-#include "starboard/log.h"
-#include "starboard/time.h"
-
 uint64_t SbSystemGetRandomUInt64() {
-  // TODO: This is DEFINITELY not cryptographically secure.
-  static bool initialized = false;
-  if (!initialized) {
-    srand(GetTickCount());
-    initialized = true;
-  }
-  return (static_cast<uint64_t>(std::rand()) << 32) | rand();
+  uint64_t return_value = 0;
+  SbSystemGetRandomData(&return_value, sizeof(return_value));
+  return return_value;
 }
diff --git a/src/starboard/shared/win32/thread_create.cc b/src/starboard/shared/win32/thread_create.cc
index a579c0b..2b14f92 100644
--- a/src/starboard/shared/win32/thread_create.cc
+++ b/src/starboard/shared/win32/thread_create.cc
@@ -19,13 +19,17 @@
 
 #include "starboard/log.h"
 #include "starboard/once.h"
+#include "starboard/shared/win32/error_utils.h"
 #include "starboard/shared/win32/thread_private.h"
 #include "starboard/shared/win32/wchar_utils.h"
 
-using starboard::shared::win32::GetThreadSubsystemSingleton;
-using starboard::shared::win32::SbThreadPrivate;
-using starboard::shared::win32::ThreadSubsystemSingleton;
-using starboard::shared::win32::wchar_tToUTF8;
+namespace sbwin32 = starboard::shared::win32;
+
+using sbwin32::DebugLogWinError;
+using sbwin32::GetThreadSubsystemSingleton;
+using sbwin32::SbThreadPrivate;
+using sbwin32::ThreadSubsystemSingleton;
+using sbwin32::wchar_tToUTF8;
 
 namespace {
 
@@ -33,30 +37,6 @@
   SetLastError(0);
 }
 
-// Checks for system errors and logs a human-readable error if GetLastError()
-// returns an error code. Noops on non-debug builds.
-void DebugLogWinError() {
-#if defined(_DEBUG)
-  DWORD error_code = GetLastError();
-  if (!error_code)
-    return;
-
-  LPWSTR error_message;
-  HRESULT hresult = HRESULT_FROM_WIN32(error_code);
-  int message_size = FormatMessage(
-      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
-          FORMAT_MESSAGE_IGNORE_INSERTS,
-      nullptr,  // Unused with FORMAT_MESSAGE_FROM_SYSTEM.
-      hresult, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-      (LPTSTR)&error_message,
-      0,  // Minimum size for output buffer.
-      nullptr);
-  SB_DCHECK(message_size);
-  SB_LOG(ERROR) << wchar_tToUTF8(error_message);
-  LocalFree(error_message);
-#endif  // defined(_DEBUG)
-}
-
 class ThreadCreateInfo {
  public:
   SbThreadPrivate thread_private_;
@@ -133,9 +113,12 @@
 }
 }  // namespace
 
+// Note that SetThreadAffinityMask() is not available on some
+// platforms (eg UWP). If it's necessary for a non-UWP platform,
+// please fork this implementation for UWP.
 SbThread SbThreadCreate(int64_t stack_size,
                         SbThreadPriority priority,
-                        SbThreadAffinity affinity,
+                        SbThreadAffinity /*affinity*/,
                         bool joinable,
                         const char* name,
                         SbThreadEntryPoint entry_point,
@@ -161,15 +144,6 @@
   SB_DCHECK(handle);
   info->thread_private_.handle_ = reinterpret_cast<HANDLE>(handle);
   ResetWinError();
-  if (affinity != kSbThreadNoAffinity &&
-      !SetThreadAffinityMask(info->thread_private_.handle_,
-                             static_cast<DWORD_PTR>(affinity)) &&
-      !GetLastError()) {
-    SB_LOG(ERROR) << "Failed to set affinity for thread " << (name ? name : "")
-                  << ". Attempted to set affinity to: " << affinity;
-    DebugLogWinError();
-  }
-  ResetWinError();
   if (priority != kSbThreadNoPriority &&
       !SetThreadPriority(info->thread_private_.handle_,
                          SbThreadPriorityToWin32Priority(priority)) &&
diff --git a/src/starboard/shared/win32/time_zone_get_name.cc b/src/starboard/shared/win32/time_zone_get_name.cc
new file mode 100644
index 0000000..6b2be53
--- /dev/null
+++ b/src/starboard/shared/win32/time_zone_get_name.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 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/time_zone.h"
+
+#include <string>
+#include <Windows.h>
+
+#include "starboard/once.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+namespace {
+class TimeZoneString {
+ public:
+  static TimeZoneString* Get();
+  const char* value() const { return value_.c_str(); }
+
+ private:
+  TimeZoneString() {
+    DYNAMIC_TIME_ZONE_INFORMATION time_zone_info;
+    DWORD zone_id = GetDynamicTimeZoneInformation(&time_zone_info);
+
+    std::wstring wide_string = time_zone_info.TimeZoneKeyName;
+    value_ = starboard::shared::win32::wchar_tToUTF8(wide_string.c_str());
+  }
+  std::string value_;
+};
+
+SB_ONCE_INITIALIZE_FUNCTION(TimeZoneString, TimeZoneString::Get);
+}  // namespace.
+
+const char* SbTimeZoneGetName() {
+  const char* output = TimeZoneString::Get()->value();
+  return output;
+}
diff --git a/src/starboard/stub/application_stub.cc b/src/starboard/stub/application_stub.cc
index f48bfdd..20614d9 100644
--- a/src/starboard/stub/application_stub.cc
+++ b/src/starboard/stub/application_stub.cc
@@ -21,39 +21,31 @@
 namespace stub {
 
 ApplicationStub::ApplicationStub() {
-  SB_NOTIMPLEMENTED();
 }
 
 ApplicationStub::~ApplicationStub() {
-  SB_NOTIMPLEMENTED();
 }
 
 void ApplicationStub::Initialize() {
-  SB_NOTIMPLEMENTED();
 }
 
 void ApplicationStub::Teardown() {
-  SB_NOTIMPLEMENTED();
 }
 
 bool ApplicationStub::MayHaveSystemEvents() {
-  SB_NOTIMPLEMENTED();
   return false;
 }
 
 shared::starboard::Application::Event* ApplicationStub::PollNextSystemEvent() {
-  SB_NOTIMPLEMENTED();
   return NULL;
 }
 
 shared::starboard::Application::Event*
 ApplicationStub::WaitForSystemEventWithTimeout(SbTime time) {
-  SB_NOTIMPLEMENTED();
   return NULL;
 }
 
 void ApplicationStub::WakeSystemEventWait() {
-  SB_NOTIMPLEMENTED();
 }
 
 }  // namespace stub
diff --git a/src/starboard/time_zone.h b/src/starboard/time_zone.h
index 25ac711..e3bf9c6 100644
--- a/src/starboard/time_zone.h
+++ b/src/starboard/time_zone.h
@@ -35,13 +35,24 @@
 // Gets the system's current SbTimeZone in minutes.
 SB_EXPORT SbTimeZone SbTimeZoneGetCurrent();
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 // Gets the three-letter code of the current timezone in standard time,
 // regardless of current Daylight Savings Time status. (e.g. "PST")
+#else
+// Gets a string representation of the current timezone. Note that the string
+// representation can either be standard or daylight saving time. The output
+// can be of the form:
+//   1) A three-letter abbreviation such as "PST" or "PDT" (preferred).
+//   2) A time zone identifier such as "America/Los_Angeles"
+//   3) An un-abbreviated name such as "Pacific Standard Time".
+#endif
 SB_EXPORT const char* SbTimeZoneGetName();
 
+#if SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 // Gets the three-letter code of the current timezone in Daylight Savings Time,
 // regardless of current DST status. (e.g. "PDT")
 SB_EXPORT const char* SbTimeZoneGetDstName();
+#endif  // SB_API_VERSION < SB_TIME_ZONE_FLEXIBLE_API_VERSION
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/src/starboard/win/console/gyp_configuration.gypi b/src/starboard/win/console/gyp_configuration.gypi
index ef90ebd..0821e08 100644
--- a/src/starboard/win/console/gyp_configuration.gypi
+++ b/src/starboard/win/console/gyp_configuration.gypi
@@ -24,70 +24,16 @@
     'default_configuration': 'win-console_debug',
     'configurations': {
       'win-console_debug': {
-        'inherit_from': ['debug_base', 'msvs_base'],
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '0',
-            'BasicRuntimeChecks': '3', # Check stack frame validity and check for uninitialized variables at run time.
-            'AdditionalOptions': [
-              '/MDd', # Use debug multithreaded library.
-              '/GS',
-            ],
-          },
-          'VCLinkerTool': {
-            'AdditionalDependencies': ['dbghelp.lib'],
-            'LinkIncremental': '2',  # INCREMENTAL:YES
-          },
-        },
+        'inherit_from': ['msvs_debug'],
       },
       'win-console_devel': {
-        'inherit_from': ['devel_base', 'msvs_base'],
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '2',
-            'AdditionalOptions': [
-              '/MDd', # Use debug multithreaded library.
-              '/GS',
-            ],
-          },
-          'VCLinkerTool': {
-            'AdditionalDependencies': ['dbghelp.lib'],
-            'LinkIncremental': '2',  # INCREMENTAL:YES
-          },
-        },
+       'inherit_from': ['msvs_devel'],
       },
       'win-console_qa': {
-        'inherit_from': ['qa_base', 'msvs_base'],
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '2',
-            'AdditionalOptions': [
-              '/MD', # Use release multithreaded library.
-            ],
-          },
-          'VCLinkerTool': {
-            'AdditionalDependencies': ['dbghelp.lib'],
-            'LinkIncremental': '1',  # INCREMENTAL:NO
-            'OptimizeReferences' : '2',  # OPT:REF
-            'EnableCOMDATFolding' : '2',  # OPT:ICF
-          },
-        },
+        'inherit_from': ['msvs_qa'],
       },
       'win-console_gold': {
-        'inherit_from': ['gold_base', 'msvs_base'],
-         'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '2',
-            'AdditionalOptions': [
-              '/MD', # Use release multithreaded library.
-            ],
-          },
-          'VCLinkerTool': {
-            'LinkIncremental': '1',  # INCREMENTAL:NO
-            'OptimizeReferences' : '2',  # OPT:REF
-            'EnableCOMDATFolding' : '2',  # OPT:ICF
-          },
-        },
+        'inherit_from': ['msvs_gold'],
       },
     },  # end of configurations
   },
diff --git a/src/starboard/win/shared/main.cc b/src/starboard/win/console/main.cc
similarity index 95%
rename from src/starboard/win/shared/main.cc
rename to src/starboard/win/console/main.cc
index 928cd84..a129991 100644
--- a/src/starboard/win/shared/main.cc
+++ b/src/starboard/win/console/main.cc
@@ -20,9 +20,9 @@
 #include <vector>
 
 #include "starboard/configuration.h"
-#include "starboard/shared/uwp/application_uwp.h"
 #include "starboard/shared/win32/thread_private.h"
 #include "starboard/shared/win32/wchar_utils.h"
+#include "starboard/stub/application_stub.h"
 
 using starboard::shared::win32::wchar_tToUTF8;
 
@@ -59,7 +59,7 @@
     utf8_args.push_back(it->data());
   }
 
-  starboard::shared::uwp::ApplicationUwp application;
+  starboard::stub::ApplicationStub application;
   int return_value = application.Run(static_cast<int>(utf8_args.size()),
                                      const_cast<char**>(utf8_args.data()));
 
diff --git a/src/starboard/win/console/starboard_platform.gyp b/src/starboard/win/console/starboard_platform.gyp
index bcfd1cb..653db66 100644
--- a/src/starboard/win/console/starboard_platform.gyp
+++ b/src/starboard/win/console/starboard_platform.gyp
@@ -13,14 +13,20 @@
 # limitations under the License.
 {
   'includes': [ '../shared/starboard_platform.gypi' ],
-  'sources': [
-    'atomic_public.h',
-    'configuration_public.h',
-    'thread_types_public.h',
-  ],
   'variables': {
     'starboard_platform_dependent_sources': [
+      'atomic_public.h',
+      'configuration_public.h',
+      'main.cc',
+      'thread_types_public.h',
       '../shared/system_get_path.cc',
+      '<(DEPTH)/starboard/shared/stub/window_create.cc',
+      '<(DEPTH)/starboard/shared/stub/window_destroy.cc',
+      '<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
+      '<(DEPTH)/starboard/shared/stub/window_get_size.cc',
+      '<(DEPTH)/starboard/shared/stub/window_set_default_options.cc',
+      '<(DEPTH)/starboard/stub/application_stub.cc',
+      '<(DEPTH)/starboard/stub/application_stub.h',
     ],
   },
 }
diff --git a/src/starboard/win/shared/configuration_public.h b/src/starboard/win/shared/configuration_public.h
index 94eb71c..47521b3 100644
--- a/src/starboard/win/shared/configuration_public.h
+++ b/src/starboard/win/shared/configuration_public.h
@@ -223,7 +223,10 @@
 
 // The current platform's maximum number of files that can be opened at the
 // same time by one process.
-#define SB_FILE_MAX_OPEN 64
+// This is set to MAXIMUM_WAIT_OBJECTS - 1, since we use WaitForMultipleEvents
+// and that only supports MAXIMUM_WAIT_OBJECTS events.  The -1 is since we
+// use a dummy event to wake up the socket.
+#define SB_FILE_MAX_OPEN 63
 
 // The current platform's file path component separator character. This is the
 // character that appears after a directory in a file path. For example, the
diff --git a/src/starboard/win/shared/gyp_configuration.gypi b/src/starboard/win/shared/gyp_configuration.gypi
index b9fa447..62a2713 100644
--- a/src/starboard/win/shared/gyp_configuration.gypi
+++ b/src/starboard/win/shared/gyp_configuration.gypi
@@ -16,8 +16,8 @@
     'target_arch': 'x64',
     'target_os': 'win',
 
-    # Use a stub rasterizer and graphical setup.
-    'rasterizer_type': 'stub',
+    # Use a hardware rasterizer and graphical setup.
+    'rasterizer_type': 'hardware',
 
     # Link with angle
     'gl_type': 'angle',
@@ -130,6 +130,72 @@
           }],
         ],
       },
+       'msvs_debug': {
+         'inherit_from': ['debug_base', 'msvs_base'],
+         'msvs_settings': {
+           'VCCLCompilerTool': {
+             'Optimization': '0',
+             'BasicRuntimeChecks': '3', # Check stack frame validity and check for uninitialized variables at run time.
+             'AdditionalOptions': [
+               '/MDd', # Use debug multithreaded library.
+               '/GS',
+             ],
+           },
+           'VCLinkerTool': {
+             'AdditionalDependencies': ['dbghelp.lib'],
+             'LinkIncremental': '2',  # INCREMENTAL:YES
+           },
+         },
+       },
+       'msvs_devel': {
+         'inherit_from': ['devel_base', 'msvs_base'],
+         'msvs_settings': {
+           'VCCLCompilerTool': {
+             'Optimization': '2',
+             'AdditionalOptions': [
+               '/MDd', # Use debug multithreaded library.
+               '/GS',
+             ],
+           },
+           'VCLinkerTool': {
+             'AdditionalDependencies': ['dbghelp.lib'],
+             'LinkIncremental': '2',  # INCREMENTAL:YES
+           },
+         },
+       },
+       'msvs_qa': {
+         'inherit_from': ['qa_base', 'msvs_base'],
+         'msvs_settings': {
+           'VCCLCompilerTool': {
+             'Optimization': '2',
+             'AdditionalOptions': [
+               '/MD', # Use release multithreaded library.
+             ],
+           },
+           'VCLinkerTool': {
+             'AdditionalDependencies': ['dbghelp.lib'],
+             'LinkIncremental': '1',  # INCREMENTAL:NO
+             'OptimizeReferences' : '2',  # OPT:REF
+             'EnableCOMDATFolding' : '2',  # OPT:ICF
+           },
+         },
+       },
+       'msvs_gold': {
+         'inherit_from': ['gold_base', 'msvs_base'],
+          'msvs_settings': {
+           'VCCLCompilerTool': {
+             'Optimization': '2',
+             'AdditionalOptions': [
+               '/MD', # Use release multithreaded library.
+             ],
+           },
+           'VCLinkerTool': {
+             'LinkIncremental': '1',  # INCREMENTAL:NO
+             'OptimizeReferences' : '2',  # OPT:REF
+             'EnableCOMDATFolding' : '2',  # OPT:ICF
+           },
+         },
+       },
     },
     'defines': [
       # Disable suggestions to switch to Microsoft-specific secure CRT.
diff --git a/src/starboard/win/shared/starboard_platform.gypi b/src/starboard/win/shared/starboard_platform.gypi
index c059193..3df57c9 100644
--- a/src/starboard/win/shared/starboard_platform.gypi
+++ b/src/starboard/win/shared/starboard_platform.gypi
@@ -89,6 +89,7 @@
         '<(DEPTH)/starboard/shared/stub/cryptography_set_authenticated_data.cc',
         '<(DEPTH)/starboard/shared/stub/cryptography_set_initialization_vector.cc',
         '<(DEPTH)/starboard/shared/stub/cryptography_transform.cc',
+        '<(DEPTH)/starboard/shared/stub/decode_target_get_info.cc',
         '<(DEPTH)/starboard/shared/stub/decode_target_release.cc',
         '<(DEPTH)/starboard/shared/stub/drm_close_session.cc',
         '<(DEPTH)/starboard/shared/stub/drm_create_system.cc',
@@ -125,13 +126,6 @@
         '<(DEPTH)/starboard/shared/stub/player_set_volume.cc',
         '<(DEPTH)/starboard/shared/stub/player_write_end_of_stream.cc',
         '<(DEPTH)/starboard/shared/stub/player_write_sample.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_add.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_create.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_destroy.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_remove.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait_timed.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_waiter_wake_up.cc',
         '<(DEPTH)/starboard/shared/stub/storage_close_record.cc',
         '<(DEPTH)/starboard/shared/stub/storage_delete_record.cc',
         '<(DEPTH)/starboard/shared/stub/storage_get_record_size.cc',
@@ -148,7 +142,6 @@
         '<(DEPTH)/starboard/shared/stub/system_get_locale_id.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_number_of_processors.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_property.cc',
-        '<(DEPTH)/starboard/shared/stub/system_get_random_data.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_stack.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_total_cpu_memory.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_total_gpu_memory.cc',
@@ -165,16 +158,11 @@
         '<(DEPTH)/starboard/shared/stub/system_sort.cc',
         '<(DEPTH)/starboard/shared/stub/system_symbolize.cc',
         '<(DEPTH)/starboard/shared/stub/time_zone_get_dst_name.cc',
-        '<(DEPTH)/starboard/shared/stub/time_zone_get_name.cc',
         '<(DEPTH)/starboard/shared/stub/user_get_current.cc',
         '<(DEPTH)/starboard/shared/stub/user_get_property.cc',
         '<(DEPTH)/starboard/shared/stub/user_get_signed_in.cc',
-        '<(DEPTH)/starboard/shared/stub/window_create.cc',
-        '<(DEPTH)/starboard/shared/stub/window_destroy.cc',
-        '<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
-        '<(DEPTH)/starboard/shared/stub/window_get_size.cc',
-        '<(DEPTH)/starboard/shared/stub/window_set_default_options.cc',
         '<(DEPTH)/starboard/shared/win32/atomic_public.h',
+        '<(DEPTH)/starboard/shared/win32/auto_event_handle.h',
         '<(DEPTH)/starboard/shared/win32/byte_swap.cc',
         '<(DEPTH)/starboard/shared/win32/condition_variable_broadcast.cc',
         '<(DEPTH)/starboard/shared/win32/condition_variable_create.cc',
@@ -188,6 +176,8 @@
         '<(DEPTH)/starboard/shared/win32/directory_get_next.cc',
         '<(DEPTH)/starboard/shared/win32/directory_internal.h',
         '<(DEPTH)/starboard/shared/win32/directory_open.cc',
+        '<(DEPTH)/starboard/shared/win32/error_utils.cc',
+        '<(DEPTH)/starboard/shared/win32/error_utils.h',
         '<(DEPTH)/starboard/shared/win32/file_can_open.cc',
         '<(DEPTH)/starboard/shared/win32/file_close.cc',
         '<(DEPTH)/starboard/shared/win32/file_delete.cc',
@@ -251,12 +241,21 @@
         '<(DEPTH)/starboard/shared/win32/socket_set_tcp_keep_alive.cc',
         '<(DEPTH)/starboard/shared/win32/socket_set_tcp_no_delay.cc',
         '<(DEPTH)/starboard/shared/win32/socket_set_tcp_window_scaling.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_add.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_create.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_destroy.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_internal.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_remove.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_wait.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_wait_timed.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_waiter_wake_up.cc',
         '<(DEPTH)/starboard/shared/win32/string_compare_no_case.cc',
         '<(DEPTH)/starboard/shared/win32/string_compare_no_case_n.cc',
         '<(DEPTH)/starboard/shared/win32/string_compare_wide.cc',
         '<(DEPTH)/starboard/shared/win32/string_format.cc',
         '<(DEPTH)/starboard/shared/win32/string_format_wide.cc',
         '<(DEPTH)/starboard/shared/win32/system_break_into_debugger.cc',
+        '<(DEPTH)/starboard/shared/win32/system_get_random_data.cc',
         '<(DEPTH)/starboard/shared/win32/system_get_random_uint64.cc',
         '<(DEPTH)/starboard/shared/win32/thread_create.cc',
         '<(DEPTH)/starboard/shared/win32/thread_create_local_key.cc',
@@ -279,12 +278,10 @@
         '<(DEPTH)/starboard/shared/win32/time_get_monotonic_now.cc',
         '<(DEPTH)/starboard/shared/win32/time_get_now.cc',
         '<(DEPTH)/starboard/shared/win32/time_zone_get_current.cc',
+        '<(DEPTH)/starboard/shared/win32/time_zone_get_name.cc',
         '<(DEPTH)/starboard/shared/win32/time_utils.h',
         '<(DEPTH)/starboard/shared/win32/wchar_utils.h',
-        '<(DEPTH)/starboard/shared/uwp/application_uwp.cc',
-        '<(DEPTH)/starboard/shared/uwp/application_uwp.h',
         'configuration_public.h',
-        'main.cc',
         # Include private stubs, if present.
         '<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "shared/stub/*.cc")',
         '<@(starboard_platform_dependent_sources)',
diff --git a/src/starboard/win/shared/system_get_path.cc b/src/starboard/win/shared/system_get_path.cc
index fdc35c2..21350df2 100644
--- a/src/starboard/win/shared/system_get_path.cc
+++ b/src/starboard/win/shared/system_get_path.cc
@@ -15,98 +15,137 @@
 #include "starboard/system.h"
 
 #include <windows.h>
+// pathcch.h must come after windows.h.
+#include <pathcch.h>
+
 #include <codecvt>
 #include <cstring>
 #include <locale>
 
-#include "Pathcch.h"
-
 #include "starboard/directory.h"
 #include "starboard/log.h"
 #include "starboard/shared/win32/directory_internal.h"
 #include "starboard/shared/win32/wchar_utils.h"
 #include "starboard/string.h"
 
+namespace {
+
+// Places up to |path_size| - 1 characters of the path to the current
+// executable in |out_path|, ensuring it is NULL-terminated. Returns success
+// status. The result being greater than |path_size| - 1 characters is a
+// failure. |out_path| may be written to in unsuccessful cases.
 bool GetExecutablePath(char* out_path, int path_size) {
   if (!out_path || !path_size) {
     return false;
   }
 
-  static const int kPathSize = SB_FILE_MAX_PATH;
+  wchar_t w_file_path[SB_FILE_MAX_PATH];
+  DWORD characters_written =
+      GetModuleFileName(NULL, w_file_path, SB_FILE_MAX_PATH);
+  if (characters_written < 1) {
+    return false;
+  }
+  std::string utf8_string =
+      starboard::shared::win32::wchar_tToUTF8(w_file_path);
+  if (utf8_string.length() >= path_size) {
+    return false;
+  }
+  return SbStringCopy(out_path, utf8_string.c_str(), path_size);
+}
+
+// Places up to |path_size| - 1 characters of the path to the directory
+// containing the current executable in |out_path|, ensuring it is
+// NULL-terminated. Returns success status. The result being greater than
+// |path_size| - 1 characters is a failure. |out_path| may be written to in
+// unsuccessful cases.
+bool GetExecutableDirectory(char* out_path, int path_size) {
+  if (!out_path || !path_size) {
+    return false;
+  }
 
   wchar_t w_file_path[SB_FILE_MAX_PATH];
   DWORD characters_written =
       GetModuleFileName(NULL, w_file_path, SB_FILE_MAX_PATH);
-  if (characters_written == 0) {
+  if (characters_written < 1) {
     return false;
   }
   PathCchRemoveFileSpec(w_file_path, SB_FILE_MAX_PATH);
   std::string utf8_string =
-      starboard::shared::win32::wchar_tToUTF8(w_file_path, SB_FILE_MAX_PATH);
-  return SbStringCopy(out_path, utf8_string.c_str(), SB_FILE_MAX_PATH);
+      starboard::shared::win32::wchar_tToUTF8(w_file_path);
+  if (utf8_string.length() >= path_size) {
+    return false;
+  }
+  return SbStringCopy(out_path, utf8_string.c_str(), path_size);
 }
 
+// Places up to |path_size| - 1 characters of the path to the content directory
+// in |out_path|, ensuring it is NULL-terminated. Returns success
+// status. The result being greater than |path_size| - 1 characters is a
+// failure. |out_path| may be written to in unsuccessful cases.
+bool GetContentPath(char* out_path, int path_size) {
+  if (!out_path || !path_size) {
+    return false;
+  }
+  char file_path[SB_FILE_MAX_PATH];
+  file_path[0] = '\0';
+  if (!GetExecutableDirectory(file_path, path_size)) {
+    return false;
+  }
+  if (SbStringConcat(file_path, "\\content\\data", SB_FILE_MAX_PATH) >=
+      path_size) {
+    return false;
+  }
+  return SbStringCopy(out_path, file_path, path_size);
+}
+
+bool CreateAndGetTempPath(char* out_path, int path_size) {
+  if (!out_path || !path_size) {
+    return false;
+  }
+  wchar_t w_file_path[SB_FILE_MAX_PATH];
+  w_file_path[0] = L'\0';
+
+  DWORD characters_written = GetTempPathW(SB_FILE_MAX_PATH, w_file_path);
+  if (characters_written >= (path_size + 1) || characters_written < 1) {
+    return false;
+  }
+  // Remove the last slash, to match other Starboard implementations.
+  w_file_path[characters_written - 1] = L'\0';
+
+  std::string utf8_string =
+      starboard::shared::win32::wchar_tToUTF8(w_file_path);
+
+  if (SbStringCopy(out_path, utf8_string.c_str(), path_size) >= path_size) {
+    return false;
+  }
+  SbDirectoryCreate(out_path);
+
+  size_t length = SbStringGetLength(out_path);
+  if (length < 1 || length > path_size) {
+    return false;
+  }
+  return true;
+}
+}  // namespace
+
 // Note: This function is only minimally implemented to allow tests to run.
 bool SbSystemGetPath(SbSystemPathId path_id, char* out_path, int path_size) {
   if (!out_path || !path_size) {
     return false;
   }
 
-  static const int kPathSize = SB_FILE_MAX_PATH;
-
-  char file_path[kPathSize];
-  file_path[0] = '\0';
-
   switch (path_id) {
-    case kSbSystemPathContentDirectory: {
-      if (!GetExecutablePath(file_path, kPathSize)) {
-        return false;
-      }
-      if (SbStringConcat(file_path, "/content/data", kPathSize) >= kPathSize) {
-        return false;
-      }
-      SbStringCopy(out_path, file_path, path_size);
-      break;
-    }
-    case kSbSystemPathTempDirectory: {
-      wchar_t w_file_path[kPathSize];
-      w_file_path[0] = '\0';
-
-      DWORD characters_written = GetTempPathW(kPathSize, w_file_path);
-      if (characters_written >= (kPathSize - 1)) {
-        return false;
-      }
-
-      if (characters_written < 1) {
-        return false;
-      }
-      // Remove the last slash, to match other Starboard implementations.
-      w_file_path[characters_written - 1] = L'\0';
-
-      std::string utf8_string =
-          starboard::shared::win32::wchar_tToUTF8(w_file_path);
-
-      if (SbStringCopy(file_path, utf8_string.c_str(), kPathSize) >=
-          kPathSize) {
-        return false;
-      }
-      SbDirectoryCreate(file_path);
-
-      size_t length = SbStringGetLength(file_path);
-      if (length < 1 || length > path_size) {
-        return false;
-      }
-
-      SbStringCopy(out_path, file_path, path_size);
-      break;
-    }
-    case kSbSystemPathExecutableFile: {
+    case kSbSystemPathContentDirectory:
+      return GetContentPath(out_path, path_size);
+    case kSbSystemPathDebugOutputDirectory:
+      return SbSystemGetPath(kSbSystemPathTempDirectory, out_path, path_size);
+    case kSbSystemPathExecutableFile:
       return GetExecutablePath(out_path, path_size);
-    }
+    case kSbSystemPathTempDirectory:
+      return CreateAndGetTempPath(out_path, path_size);
     // TODO: implement all the other cases.
     default:
       SB_NOTIMPLEMENTED();
       return false;
   }
-  return true;
 }
diff --git a/src/third_party/angle/gyp/common_defines.gypi b/src/third_party/angle/gyp/common_defines.gypi
index bce49c4..fc2b7b9 100644
--- a/src/third_party/angle/gyp/common_defines.gypi
+++ b/src/third_party/angle/gyp/common_defines.gypi
@@ -52,6 +52,13 @@
         {
             'defines': [ 'COMPONENT_BUILD' ],
         }],
+        ['target_os=="win"',
+        {
+            'defines': [
+                'WINAPI_FAMILY=WINAPI_FAMILY_APP',
+                ' __WRL_NO_DEFAULT_LIB__',
+             ],
+        }],
     ],
     'msvs_settings':
     {
diff --git a/src/third_party/angle/include/EGL/egl.h b/src/third_party/angle/include/EGL/egl.h
index 29f30d9..b32c505 100644
--- a/src/third_party/angle/include/EGL/egl.h
+++ b/src/third_party/angle/include/EGL/egl.h
@@ -1,6 +1,8 @@
 #ifndef __egl_h_
 #define __egl_h_ 1
 
+#include "starboard/types.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/third_party/angle/include/EGL/eglplatform.h b/src/third_party/angle/include/EGL/eglplatform.h
index 0c70ae4..d4b50bf 100644
--- a/src/third_party/angle/include/EGL/eglplatform.h
+++ b/src/third_party/angle/include/EGL/eglplatform.h
@@ -73,6 +73,14 @@
  * implementations.
  */
 
+#if defined(STARBOARD)
+
+typedef void* EGLNativeDisplayType;
+typedef void* EGLNativePixmapType;
+typedef void* EGLNativeWindowType;
+
+#else
+
 #if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
@@ -125,6 +133,7 @@
 #error "Platform not recognized"
 #endif
 
+#endif  // STARBOARD
 /* EGL 1.2 types, renamed for consistency in EGL 1.3 */
 typedef EGLNativeDisplayType NativeDisplayType;
 typedef EGLNativePixmapType  NativePixmapType;
diff --git a/src/third_party/angle/src/common/platform.h b/src/third_party/angle/src/common/platform.h
index 2fe55e8..ee219eb 100644
--- a/src/third_party/angle/src/common/platform.h
+++ b/src/third_party/angle/src/common/platform.h
@@ -9,7 +9,9 @@
 #ifndef COMMON_PLATFORM_H_
 #define COMMON_PLATFORM_H_
 
-#if defined(_WIN32) || defined(_WIN64)
+#if defined(STARBOARD)
+#   define ANGLE_PLATFORM_WINDOWS 1
+#elif defined(_WIN32) || defined(_WIN64)
 #   define ANGLE_PLATFORM_WINDOWS 1
 #elif defined(__APPLE__)
 #   define ANGLE_PLATFORM_APPLE 1
diff --git a/src/third_party/icu/source/i18n/timezone.cpp b/src/third_party/icu/source/i18n/timezone.cpp
index a6a2e04..974ecbe 100644
--- a/src/third_party/icu/source/i18n/timezone.cpp
+++ b/src/third_party/icu/source/i18n/timezone.cpp
@@ -413,8 +413,34 @@
     return createSystemTimeZone(id, ec);
 }
 
+// winIdOut is only modified if the creation of TimeZone was successful. This
+// allows the input variable to also be the output variable.
+TimeZone* CreateTimeZoneFromWindowsID(const UnicodeString& id,
+                                      UnicodeString* winIdOut) {
+  UErrorCode status = U_ZERO_ERROR;
+  UnicodeString idOut;
+  TimeZone::getIDForWindowsID(id, NULL, idOut, status);
+
+  if ((idOut.length() > 0) && (status == U_ZERO_ERROR)) {
+    idOut.append((UChar)0);
+    idOut.truncate(idOut.length()-1);
+
+    TimeZone* time_zone = createSystemTimeZone(idOut);
+    if (time_zone) {
+      // SUCCESS!!
+      // Update variables.
+      if (winIdOut) {
+        *winIdOut = idOut;
+      }
+      return time_zone;
+    }
+  }
+
+  return NULL;
 }
 
+}  // namespace anonymous.
+
 TimeZone* U_EXPORT2
 TimeZone::createTimeZone(const UnicodeString& ID)
 {
@@ -478,6 +504,16 @@
     hostStrID.truncate(hostStrID.length()-1);
     hostZone = createSystemTimeZone(hostStrID);
 
+#ifdef STARBOARD
+    // Certain platforms may return an id that is un-abbreviated, such as
+    // "Pacific Standard Time". Therefore attempt to create a TimeZone for
+    // these platforms.
+    if (!hostZone) {
+      // hostStrID will be mutated iff hostZone was successfully created.
+      hostZone = CreateTimeZoneFromWindowsID(hostStrID, &hostStrID);
+    }
+#endif
+
 #if U_PLATFORM_USES_ONLY_WIN32_API || defined(__LB_XB1__)
     // hostID points to a heap-allocated location on Windows.
     uprv_free(const_cast<char *>(hostID));
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2.S b/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2.S
deleted file mode 100644
index f3b1629..0000000
--- a/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2.S
+++ /dev/null
@@ -1,1618 +0,0 @@
-;
-; PA-RISC 2.0 implementation of bn_asm code, based on the
-; 64-bit version of the code.  This code is effectively the
-; same as the 64-bit version except the register model is
-; slightly different given all values must be 32-bit between
-; function calls.  Thus the 64-bit return values are returned
-; in %ret0 and %ret1 vs just %ret0 as is done in 64-bit
-;
-;
-; This code is approximately 2x faster than the C version
-; for RSA/DSA.
-;
-; See http://devresource.hp.com/  for more details on the PA-RISC
-; architecture.  Also see the book "PA-RISC 2.0 Architecture"
-; by Gerry Kane for information on the instruction set architecture.
-;
-; Code written by Chris Ruemmler (with some help from the HP C
-; compiler).
-;
-; The code compiles with HP's assembler
-;
-
-	.level	2.0N
-	.space	$TEXT$
-	.subspa	$CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY
-
-;
-; Global Register definitions used for the routines.
-;
-; Some information about HP's runtime architecture for 32-bits.
-;
-; "Caller save" means the calling function must save the register
-; if it wants the register to be preserved.
-; "Callee save" means if a function uses the register, it must save
-; the value before using it.
-;
-; For the floating point registers 
-;
-;    "caller save" registers: fr4-fr11, fr22-fr31
-;    "callee save" registers: fr12-fr21
-;    "special" registers: fr0-fr3 (status and exception registers)
-;
-; For the integer registers
-;     value zero             :  r0
-;     "caller save" registers: r1,r19-r26
-;     "callee save" registers: r3-r18
-;     return register        :  r2  (rp)
-;     return values          ; r28,r29  (ret0,ret1)
-;     Stack pointer          ; r30  (sp) 
-;     millicode return ptr   ; r31  (also a caller save register)
-
-
-;
-; Arguments to the routines
-;
-r_ptr       .reg %r26
-a_ptr       .reg %r25
-b_ptr       .reg %r24
-num         .reg %r24
-n           .reg %r23
-
-;
-; Note that the "w" argument for bn_mul_add_words and bn_mul_words
-; is passed on the stack at a delta of -56 from the top of stack
-; as the routine is entered.
-;
-
-;
-; Globals used in some routines
-;
-
-top_overflow .reg %r23
-high_mask    .reg %r22    ; value 0xffffffff80000000L
-
-
-;------------------------------------------------------------------------------
-;
-; bn_mul_add_words
-;
-;BN_ULONG bn_mul_add_words(BN_ULONG *r_ptr, BN_ULONG *a_ptr, 
-;								int num, BN_ULONG w)
-;
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg3 = num
-; -56(sp) =  w
-;
-; Local register definitions
-;
-
-fm1          .reg %fr22
-fm           .reg %fr23
-ht_temp      .reg %fr24
-ht_temp_1    .reg %fr25
-lt_temp      .reg %fr26
-lt_temp_1    .reg %fr27
-fm1_1        .reg %fr28
-fm_1         .reg %fr29
-
-fw_h         .reg %fr7L
-fw_l         .reg %fr7R
-fw           .reg %fr7
-
-fht_0        .reg %fr8L
-flt_0        .reg %fr8R
-t_float_0    .reg %fr8
-
-fht_1        .reg %fr9L
-flt_1        .reg %fr9R
-t_float_1    .reg %fr9
-
-tmp_0        .reg %r31
-tmp_1        .reg %r21
-m_0          .reg %r20 
-m_1          .reg %r19 
-ht_0         .reg %r1  
-ht_1         .reg %r3
-lt_0         .reg %r4
-lt_1         .reg %r5
-m1_0         .reg %r6 
-m1_1         .reg %r7 
-rp_val       .reg %r8
-rp_val_1     .reg %r9
-
-bn_mul_add_words
-	.export	bn_mul_add_words,entry,NO_RELOCATION,LONG_RETURN
-	.proc
-	.callinfo frame=128
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-	NOP                         ; Needed to make the loop 16-byte aligned
-	NOP                         ; needed to make the loop 16-byte aligned
-
-    STD     %r5,16(%sp)         ; save r5  
-	NOP
-    STD     %r6,24(%sp)         ; save r6  
-    STD     %r7,32(%sp)         ; save r7  
-
-    STD     %r8,40(%sp)         ; save r8  
-    STD     %r9,48(%sp)         ; save r9  
-    COPY    %r0,%ret1           ; return 0 by default
-    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
-
-    CMPIB,>= 0,num,bn_mul_add_words_exit  ; if (num <= 0) then exit
-	LDO     128(%sp),%sp        ; bump stack
-
-	;
-	; The loop is unrolled twice, so if there is only 1 number
-    ; then go straight to the cleanup code.
-	;
-	CMPIB,= 1,num,bn_mul_add_words_single_top
-	FLDD    -184(%sp),fw        ; (-56-128) load up w into fw (fw_h/fw_l)
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
-    ; two 32-bit mutiplies can be issued per cycle.
-    ; 
-bn_mul_add_words_unroll2
-
-    FLDD    0(a_ptr),t_float_0       ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    FLDD    8(a_ptr),t_float_1       ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    LDD     0(r_ptr),rp_val          ; rp[0]
-    LDD     8(r_ptr),rp_val_1        ; rp[1]
-
-    XMPYU   fht_0,fw_l,fm1           ; m1[0] = fht_0*fw_l
-    XMPYU   fht_1,fw_l,fm1_1         ; m1[1] = fht_1*fw_l
-    FSTD    fm1,-16(%sp)             ; -16(sp) = m1[0]
-    FSTD    fm1_1,-48(%sp)           ; -48(sp) = m1[1]
-
-    XMPYU   flt_0,fw_h,fm            ; m[0] = flt_0*fw_h
-    XMPYU   flt_1,fw_h,fm_1          ; m[1] = flt_1*fw_h
-    FSTD    fm,-8(%sp)               ; -8(sp) = m[0]
-    FSTD    fm_1,-40(%sp)            ; -40(sp) = m[1]
-
-    XMPYU   fht_0,fw_h,ht_temp       ; ht_temp   = fht_0*fw_h
-    XMPYU   fht_1,fw_h,ht_temp_1     ; ht_temp_1 = fht_1*fw_h
-    FSTD    ht_temp,-24(%sp)         ; -24(sp)   = ht_temp
-    FSTD    ht_temp_1,-56(%sp)       ; -56(sp)   = ht_temp_1
-
-    XMPYU   flt_0,fw_l,lt_temp       ; lt_temp = lt*fw_l
-    XMPYU   flt_1,fw_l,lt_temp_1     ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)         ; -32(sp) = lt_temp 
-    FSTD    lt_temp_1,-64(%sp)       ; -64(sp) = lt_temp_1 
-
-    LDD     -8(%sp),m_0              ; m[0] 
-    LDD     -40(%sp),m_1             ; m[1]
-    LDD     -16(%sp),m1_0            ; m1[0]
-    LDD     -48(%sp),m1_1            ; m1[1]
-
-    LDD     -24(%sp),ht_0            ; ht[0]
-    LDD     -56(%sp),ht_1            ; ht[1]
-    ADD,L   m1_0,m_0,tmp_0           ; tmp_0 = m[0] + m1[0]; 
-    ADD,L   m1_1,m_1,tmp_1           ; tmp_1 = m[1] + m1[1]; 
-
-    LDD     -32(%sp),lt_0            
-    LDD     -64(%sp),lt_1            
-    CMPCLR,*>>= tmp_0,m1_0, %r0      ; if (m[0] < m1[0])
-    ADD,L   ht_0,top_overflow,ht_0   ; ht[0] += (1<<32)
-
-    CMPCLR,*>>= tmp_1,m1_1,%r0       ; if (m[1] < m1[1])
-    ADD,L   ht_1,top_overflow,ht_1   ; ht[1] += (1<<32)
-    EXTRD,U tmp_0,31,32,m_0          ; m[0]>>32  
-    DEPD,Z  tmp_0,31,32,m1_0         ; m1[0] = m[0]<<32 
-
-    EXTRD,U tmp_1,31,32,m_1          ; m[1]>>32  
-    DEPD,Z  tmp_1,31,32,m1_1         ; m1[1] = m[1]<<32 
-    ADD,L   ht_0,m_0,ht_0            ; ht[0]+= (m[0]>>32)
-    ADD,L   ht_1,m_1,ht_1            ; ht[1]+= (m[1]>>32)
-
-    ADD     lt_0,m1_0,lt_0           ; lt[0] = lt[0]+m1[0];
-	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-    ADD     lt_1,m1_1,lt_1           ; lt[1] = lt[1]+m1[1];
-    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
-
-    ADD    %ret1,lt_0,lt_0           ; lt[0] = lt[0] + c;
-	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-    ADD     lt_0,rp_val,lt_0         ; lt[0] = lt[0]+rp[0]
-    ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-
-	LDO    -2(num),num               ; num = num - 2;
-    ADD     ht_0,lt_1,lt_1           ; lt[1] = lt[1] + ht_0 (c);
-    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
-    STD     lt_0,0(r_ptr)            ; rp[0] = lt[0]
-
-    ADD     lt_1,rp_val_1,lt_1       ; lt[1] = lt[1]+rp[1]
-    ADD,DC  ht_1,%r0,%ret1           ; ht[1]++
-    LDO     16(a_ptr),a_ptr          ; a_ptr += 2
-
-    STD     lt_1,8(r_ptr)            ; rp[1] = lt[1]
-	CMPIB,<= 2,num,bn_mul_add_words_unroll2 ; go again if more to do
-    LDO     16(r_ptr),r_ptr          ; r_ptr += 2
-
-    CMPIB,=,N 0,num,bn_mul_add_words_exit ; are we done, or cleanup last one
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_mul_add_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    LDD     0(r_ptr),rp_val           ; rp[0]
-    LDO     8(a_ptr),a_ptr            ; a_ptr++
-    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-
-    LDD     -8(%sp),m_0               
-    LDD    -16(%sp),m1_0              ; m1 = temp1 
-    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
-    LDD     -24(%sp),ht_0             
-    LDD     -32(%sp),lt_0             
-
-    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,tmp_0           ; tmp_0 = lt+m1;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-    ADD     %ret1,tmp_0,lt_0          ; lt = lt + c;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-    ADD     lt_0,rp_val,lt_0          ; lt = lt+rp[0]
-    ADD,DC  ht_0,%r0,%ret1            ; ht++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-
-bn_mul_add_words_exit
-    .EXIT
-	
-    EXTRD,U %ret1,31,32,%ret0         ; for 32-bit, return in ret0/ret1
-    LDD     -80(%sp),%r9              ; restore r9  
-    LDD     -88(%sp),%r8              ; restore r8  
-    LDD     -96(%sp),%r7              ; restore r7  
-    LDD     -104(%sp),%r6             ; restore r6  
-    LDD     -112(%sp),%r5             ; restore r5  
-    LDD     -120(%sp),%r4             ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3             ; restore r3
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
-;
-; arg0 = rp
-; arg1 = ap
-; arg3 = num
-; w on stack at -56(sp)
-
-bn_mul_words
-	.proc
-	.callinfo frame=128
-    .entry
-	.EXPORT	bn_mul_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-	NOP
-    STD     %r5,16(%sp)         ; save r5  
-
-    STD     %r6,24(%sp)         ; save r6  
-    STD     %r7,32(%sp)         ; save r7  
-    COPY    %r0,%ret1           ; return 0 by default
-    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
-
-    CMPIB,>= 0,num,bn_mul_words_exit
-	LDO     128(%sp),%sp    ; bump stack
-
-	;
-	; See if only 1 word to do, thus just do cleanup
-	;
-	CMPIB,= 1,num,bn_mul_words_single_top
-	FLDD    -184(%sp),fw        ; (-56-128) load up w into fw (fw_h/fw_l)
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
-    ; two 32-bit mutiplies can be issued per cycle.
-    ; 
-bn_mul_words_unroll2
-
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    FLDD    8(a_ptr),t_float_1        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    XMPYU   fht_0,fw_l,fm1            ; m1[0] = fht_0*fw_l
-    XMPYU   fht_1,fw_l,fm1_1          ; m1[1] = ht*fw_l
-
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    FSTD    fm1_1,-48(%sp)            ; -48(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    XMPYU   flt_1,fw_h,fm_1           ; m = lt*fw_h
-
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    FSTD    fm_1,-40(%sp)             ; -40(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = fht_0*fw_h
-    XMPYU   fht_1,fw_h,ht_temp_1      ; ht_temp = ht*fw_h
-
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    FSTD    ht_temp_1,-56(%sp)        ; -56(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    XMPYU   flt_1,fw_l,lt_temp_1      ; lt_temp = lt*fw_l
-
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-    FSTD    lt_temp_1,-64(%sp)        ; -64(sp) = lt 
-    LDD     -8(%sp),m_0               
-    LDD     -40(%sp),m_1              
-
-    LDD    -16(%sp),m1_0              
-    LDD    -48(%sp),m1_1              
-    LDD     -24(%sp),ht_0             
-    LDD     -56(%sp),ht_1             
-
-    ADD,L   m1_0,m_0,tmp_0            ; tmp_0 = m + m1; 
-    ADD,L   m1_1,m_1,tmp_1            ; tmp_1 = m + m1; 
-    LDD     -32(%sp),lt_0             
-    LDD     -64(%sp),lt_1             
-
-    CMPCLR,*>>= tmp_0,m1_0, %r0       ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-    CMPCLR,*>>= tmp_1,m1_1,%r0        ; if (m < m1)
-    ADD,L   ht_1,top_overflow,ht_1    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-    EXTRD,U tmp_1,31,32,m_1           ; m>>32  
-    DEPD,Z  tmp_1,31,32,m1_1          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD,L   ht_1,m_1,ht_1             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,lt_0            ; lt = lt+m1;
-	ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     lt_1,m1_1,lt_1            ; lt = lt+m1;
-    ADD,DC  ht_1,%r0,ht_1             ; ht++
-    ADD    %ret1,lt_0,lt_0            ; lt = lt + c (ret1);
-	ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     ht_0,lt_1,lt_1            ; lt = lt + c (ht_0)
-    ADD,DC  ht_1,%r0,ht_1             ; ht++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-    STD     lt_1,8(r_ptr)             ; rp[1] = lt
-
-	COPY    ht_1,%ret1                ; carry = ht
-	LDO    -2(num),num                ; num = num - 2;
-    LDO     16(a_ptr),a_ptr           ; ap += 2
-	CMPIB,<= 2,num,bn_mul_words_unroll2
-    LDO     16(r_ptr),r_ptr           ; rp++
-
-    CMPIB,=,N 0,num,bn_mul_words_exit ; are we done?
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_mul_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-
-    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-
-    LDD     -8(%sp),m_0               
-    LDD    -16(%sp),m1_0              
-    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
-    LDD     -24(%sp),ht_0             
-    LDD     -32(%sp),lt_0             
-
-    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,lt_0            ; lt= lt+m1;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     %ret1,lt_0,lt_0           ; lt = lt + c;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    COPY    ht_0,%ret1                ; copy carry
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-
-bn_mul_words_exit
-    .EXIT
-    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
-    LDD     -96(%sp),%r7              ; restore r7  
-    LDD     -104(%sp),%r6             ; restore r6  
-    LDD     -112(%sp),%r5             ; restore r5  
-    LDD     -120(%sp),%r4             ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3             ; restore r3
-	.PROCEND	
-
-;----------------------------------------------------------------------------
-;
-;void bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num)
-;
-; arg0 = rp
-; arg1 = ap
-; arg2 = num
-;
-
-bn_sqr_words
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-	NOP
-    STD     %r5,16(%sp)         ; save r5  
-
-    CMPIB,>= 0,num,bn_sqr_words_exit
-	LDO     128(%sp),%sp       ; bump stack
-
-	;
-	; If only 1, the goto straight to cleanup
-	;
-	CMPIB,= 1,num,bn_sqr_words_single_top
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-
-bn_sqr_words_unroll2
-    FLDD    0(a_ptr),t_float_0        ; a[0]
-    FLDD    8(a_ptr),t_float_1        ; a[1]
-    XMPYU   fht_0,flt_0,fm            ; m[0]
-    XMPYU   fht_1,flt_1,fm_1          ; m[1]
-
-    FSTD    fm,-24(%sp)               ; store m[0]
-    FSTD    fm_1,-56(%sp)             ; store m[1]
-    XMPYU   flt_0,flt_0,lt_temp       ; lt[0]
-    XMPYU   flt_1,flt_1,lt_temp_1     ; lt[1]
-
-    FSTD    lt_temp,-16(%sp)          ; store lt[0]
-    FSTD    lt_temp_1,-48(%sp)        ; store lt[1]
-    XMPYU   fht_0,fht_0,ht_temp       ; ht[0]
-    XMPYU   fht_1,fht_1,ht_temp_1     ; ht[1]
-
-    FSTD    ht_temp,-8(%sp)           ; store ht[0]
-    FSTD    ht_temp_1,-40(%sp)        ; store ht[1]
-    LDD     -24(%sp),m_0             
-    LDD     -56(%sp),m_1              
-
-    AND     m_0,high_mask,tmp_0       ; m[0] & Mask
-    AND     m_1,high_mask,tmp_1       ; m[1] & Mask
-    DEPD,Z  m_0,30,31,m_0             ; m[0] << 32+1
-    DEPD,Z  m_1,30,31,m_1             ; m[1] << 32+1
-
-    LDD     -16(%sp),lt_0        
-    LDD     -48(%sp),lt_1        
-    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m[0]&Mask >> 32-1
-    EXTRD,U tmp_1,32,33,tmp_1         ; tmp_1 = m[1]&Mask >> 32-1
-
-    LDD     -8(%sp),ht_0            
-    LDD     -40(%sp),ht_1           
-    ADD,L   ht_0,tmp_0,ht_0           ; ht[0] += tmp_0
-    ADD,L   ht_1,tmp_1,ht_1           ; ht[1] += tmp_1
-
-    ADD     lt_0,m_0,lt_0             ; lt = lt+m
-    ADD,DC  ht_0,%r0,ht_0             ; ht[0]++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt[0]
-    STD     ht_0,8(r_ptr)             ; rp[1] = ht[1]
-
-    ADD     lt_1,m_1,lt_1             ; lt = lt+m
-    ADD,DC  ht_1,%r0,ht_1             ; ht[1]++
-    STD     lt_1,16(r_ptr)            ; rp[2] = lt[1]
-    STD     ht_1,24(r_ptr)            ; rp[3] = ht[1]
-
-	LDO    -2(num),num                ; num = num - 2;
-    LDO     16(a_ptr),a_ptr           ; ap += 2
-	CMPIB,<= 2,num,bn_sqr_words_unroll2
-    LDO     32(r_ptr),r_ptr           ; rp += 4
-
-    CMPIB,=,N 0,num,bn_sqr_words_exit ; are we done?
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_sqr_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-
-    XMPYU   fht_0,flt_0,fm            ; m
-    FSTD    fm,-24(%sp)               ; store m
-
-    XMPYU   flt_0,flt_0,lt_temp       ; lt
-    FSTD    lt_temp,-16(%sp)          ; store lt
-
-    XMPYU   fht_0,fht_0,ht_temp       ; ht
-    FSTD    ht_temp,-8(%sp)           ; store ht
-
-    LDD     -24(%sp),m_0              ; load m
-    AND     m_0,high_mask,tmp_0       ; m & Mask
-    DEPD,Z  m_0,30,31,m_0             ; m << 32+1
-    LDD     -16(%sp),lt_0             ; lt
-
-    LDD     -8(%sp),ht_0              ; ht
-    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m&Mask >> 32-1
-    ADD     m_0,lt_0,lt_0             ; lt = lt+m
-    ADD,L   ht_0,tmp_0,ht_0           ; ht += tmp_0
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-    STD     ht_0,8(r_ptr)             ; rp[1] = ht
-
-bn_sqr_words_exit
-    .EXIT
-    LDD     -112(%sp),%r5       ; restore r5  
-    LDD     -120(%sp),%r4       ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3 
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
-;
-; arg0 = rp 
-; arg1 = ap
-; arg2 = bp 
-; arg3 = n
-
-t  .reg %r22
-b  .reg %r21
-l  .reg %r20
-
-bn_add_words
-	.proc
-    .entry
-	.callinfo
-	.EXPORT	bn_add_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-	.align 64
-
-    CMPIB,>= 0,n,bn_add_words_exit
-    COPY    %r0,%ret1           ; return 0 by default
-
-	;
-	; If 2 or more numbers do the loop
-	;
-	CMPIB,= 1,n,bn_add_words_single_top
-	NOP
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-bn_add_words_unroll2
-	LDD     0(a_ptr),t
-	LDD     0(b_ptr),b
-	ADD     t,%ret1,t                    ; t = t+c;
-	ADD,DC  %r0,%r0,%ret1                ; set c to carry
-	ADD     t,b,l                        ; l = t + b[0]
-	ADD,DC  %ret1,%r0,%ret1              ; c+= carry
-	STD     l,0(r_ptr)
-
-	LDD     8(a_ptr),t
-	LDD     8(b_ptr),b
-	ADD     t,%ret1,t                     ; t = t+c;
-	ADD,DC  %r0,%r0,%ret1                 ; set c to carry
-	ADD     t,b,l                         ; l = t + b[0]
-	ADD,DC  %ret1,%r0,%ret1               ; c+= carry
-	STD     l,8(r_ptr)
-
-	LDO     -2(n),n
-	LDO     16(a_ptr),a_ptr
-	LDO     16(b_ptr),b_ptr
-
-	CMPIB,<= 2,n,bn_add_words_unroll2
-	LDO     16(r_ptr),r_ptr
-
-    CMPIB,=,N 0,n,bn_add_words_exit ; are we done?
-
-bn_add_words_single_top
-	LDD     0(a_ptr),t
-	LDD     0(b_ptr),b
-
-	ADD     t,%ret1,t                 ; t = t+c;
-	ADD,DC  %r0,%r0,%ret1             ; set c to carry (could use CMPCLR??)
-	ADD     t,b,l                     ; l = t + b[0]
-	ADD,DC  %ret1,%r0,%ret1           ; c+= carry
-	STD     l,0(r_ptr)
-
-bn_add_words_exit
-    .EXIT
-    BVE     (%rp)
-    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
-;
-; arg0 = rp 
-; arg1 = ap
-; arg2 = bp 
-; arg3 = n
-
-t1       .reg %r22
-t2       .reg %r21
-sub_tmp1 .reg %r20
-sub_tmp2 .reg %r19
-
-
-bn_sub_words
-	.proc
-	.callinfo 
-	.EXPORT	bn_sub_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    CMPIB,>=  0,n,bn_sub_words_exit
-    COPY    %r0,%ret1           ; return 0 by default
-
-	;
-	; If 2 or more numbers do the loop
-	;
-	CMPIB,= 1,n,bn_sub_words_single_top
-	NOP
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-bn_sub_words_unroll2
-	LDD     0(a_ptr),t1
-	LDD     0(b_ptr),t2
-	SUB     t1,t2,sub_tmp1           ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret1,sub_tmp1  ; t3 = t3- c; 
-
-	CMPCLR,*>> t1,t2,sub_tmp2        ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret1
-	STD     sub_tmp1,0(r_ptr)
-
-	LDD     8(a_ptr),t1
-	LDD     8(b_ptr),t2
-	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret1,sub_tmp1   ; t3 = t3- c; 
-	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret1
-	STD     sub_tmp1,8(r_ptr)
-
-	LDO     -2(n),n
-	LDO     16(a_ptr),a_ptr
-	LDO     16(b_ptr),b_ptr
-
-	CMPIB,<= 2,n,bn_sub_words_unroll2
-	LDO     16(r_ptr),r_ptr
-
-    CMPIB,=,N 0,n,bn_sub_words_exit ; are we done?
-
-bn_sub_words_single_top
-	LDD     0(a_ptr),t1
-	LDD     0(b_ptr),t2
-	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret1,sub_tmp1   ; t3 = t3- c; 
-	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret1
-
-	STD     sub_tmp1,0(r_ptr)
-
-bn_sub_words_exit
-    .EXIT
-    BVE     (%rp)
-    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;------------------------------------------------------------------------------
-;
-; unsigned long bn_div_words(unsigned long h, unsigned long l, unsigned long d)
-;
-; arg0 = h
-; arg1 = l
-; arg2 = d
-;
-; This is mainly just output from the HP C compiler.  
-;
-;------------------------------------------------------------------------------
-bn_div_words
-	.PROC
-	.EXPORT	bn_div_words,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR,LONG_RETURN
-	.IMPORT	BN_num_bits_word,CODE
-	;--- not PIC	.IMPORT	__iob,DATA
-	;--- not PIC	.IMPORT	fprintf,CODE
-	.IMPORT	abort,CODE
-	.IMPORT	$$div2U,MILLICODE
-	.CALLINFO CALLER,FRAME=144,ENTRY_GR=%r9,SAVE_RP,ARGS_SAVED,ORDERING_AWARE
-        .ENTRY
-        STW     %r2,-20(%r30)   ;offset 0x8ec
-        STW,MA  %r3,192(%r30)   ;offset 0x8f0
-        STW     %r4,-188(%r30)  ;offset 0x8f4
-        DEPD    %r5,31,32,%r6   ;offset 0x8f8
-        STD     %r6,-184(%r30)  ;offset 0x8fc
-        DEPD    %r7,31,32,%r8   ;offset 0x900
-        STD     %r8,-176(%r30)  ;offset 0x904
-        STW     %r9,-168(%r30)  ;offset 0x908
-        LDD     -248(%r30),%r3  ;offset 0x90c
-        COPY    %r26,%r4        ;offset 0x910
-        COPY    %r24,%r5        ;offset 0x914
-        DEPD    %r25,31,32,%r4  ;offset 0x918
-        CMPB,*<>        %r3,%r0,$0006000C       ;offset 0x91c
-        DEPD    %r23,31,32,%r5  ;offset 0x920
-        MOVIB,TR        -1,%r29,$00060002       ;offset 0x924
-        EXTRD,U %r29,31,32,%r28 ;offset 0x928
-$0006002A
-        LDO     -1(%r29),%r29   ;offset 0x92c
-        SUB     %r23,%r7,%r23   ;offset 0x930
-$00060024
-        SUB     %r4,%r31,%r25   ;offset 0x934
-        AND     %r25,%r19,%r26  ;offset 0x938
-        CMPB,*<>,N      %r0,%r26,$00060046      ;offset 0x93c
-        DEPD,Z  %r25,31,32,%r20 ;offset 0x940
-        OR      %r20,%r24,%r21  ;offset 0x944
-        CMPB,*<<,N      %r21,%r23,$0006002A     ;offset 0x948
-        SUB     %r31,%r2,%r31   ;offset 0x94c
-$00060046
-$0006002E
-        DEPD,Z  %r23,31,32,%r25 ;offset 0x950
-        EXTRD,U %r23,31,32,%r26 ;offset 0x954
-        AND     %r25,%r19,%r24  ;offset 0x958
-        ADD,L   %r31,%r26,%r31  ;offset 0x95c
-        CMPCLR,*>>=     %r5,%r24,%r0    ;offset 0x960
-        LDO     1(%r31),%r31    ;offset 0x964
-$00060032
-        CMPB,*<<=,N     %r31,%r4,$00060036      ;offset 0x968
-        LDO     -1(%r29),%r29   ;offset 0x96c
-        ADD,L   %r4,%r3,%r4     ;offset 0x970
-$00060036
-        ADDIB,=,N       -1,%r8,$D0      ;offset 0x974
-        SUB     %r5,%r24,%r28   ;offset 0x978
-$0006003A
-        SUB     %r4,%r31,%r24   ;offset 0x97c
-        SHRPD   %r24,%r28,32,%r4        ;offset 0x980
-        DEPD,Z  %r29,31,32,%r9  ;offset 0x984
-        DEPD,Z  %r28,31,32,%r5  ;offset 0x988
-$0006001C
-        EXTRD,U %r4,31,32,%r31  ;offset 0x98c
-        CMPB,*<>,N      %r31,%r2,$00060020      ;offset 0x990
-        MOVB,TR %r6,%r29,$D1    ;offset 0x994
-        STD     %r29,-152(%r30) ;offset 0x998
-$0006000C
-        EXTRD,U %r3,31,32,%r25  ;offset 0x99c
-        COPY    %r3,%r26        ;offset 0x9a0
-        EXTRD,U %r3,31,32,%r9   ;offset 0x9a4
-        EXTRD,U %r4,31,32,%r8   ;offset 0x9a8
-        .CALL   ARGW0=GR,ARGW1=GR,RTNVAL=GR     ;in=25,26;out=28;
-        B,L     BN_num_bits_word,%r2    ;offset 0x9ac
-        EXTRD,U %r5,31,32,%r7   ;offset 0x9b0
-        LDI     64,%r20 ;offset 0x9b4
-        DEPD    %r7,31,32,%r5   ;offset 0x9b8
-        DEPD    %r8,31,32,%r4   ;offset 0x9bc
-        DEPD    %r9,31,32,%r3   ;offset 0x9c0
-        CMPB,=  %r28,%r20,$00060012     ;offset 0x9c4
-        COPY    %r28,%r24       ;offset 0x9c8
-        MTSARCM %r24    ;offset 0x9cc
-        DEPDI,Z -1,%sar,1,%r19  ;offset 0x9d0
-        CMPB,*>>,N      %r4,%r19,$D2    ;offset 0x9d4
-$00060012
-        SUBI    64,%r24,%r31    ;offset 0x9d8
-        CMPCLR,*<<      %r4,%r3,%r0     ;offset 0x9dc
-        SUB     %r4,%r3,%r4     ;offset 0x9e0
-$00060016
-        CMPB,=  %r31,%r0,$0006001A      ;offset 0x9e4
-        COPY    %r0,%r9 ;offset 0x9e8
-        MTSARCM %r31    ;offset 0x9ec
-        DEPD,Z  %r3,%sar,64,%r3 ;offset 0x9f0
-        SUBI    64,%r31,%r26    ;offset 0x9f4
-        MTSAR   %r26    ;offset 0x9f8
-        SHRPD   %r4,%r5,%sar,%r4        ;offset 0x9fc
-        MTSARCM %r31    ;offset 0xa00
-        DEPD,Z  %r5,%sar,64,%r5 ;offset 0xa04
-$0006001A
-        DEPDI,Z -1,31,32,%r19   ;offset 0xa08
-        AND     %r3,%r19,%r29   ;offset 0xa0c
-        EXTRD,U %r29,31,32,%r2  ;offset 0xa10
-        DEPDI,Z -1,63,32,%r6    ;offset 0xa14
-        MOVIB,TR        2,%r8,$0006001C ;offset 0xa18
-        EXTRD,U %r3,63,32,%r7   ;offset 0xa1c
-$D2
-        ;--- not PIC	ADDIL   LR'__iob-$global$,%r27,%r1      ;offset 0xa20
-        ;--- not PIC	LDIL    LR'C$7,%r21     ;offset 0xa24
-        ;--- not PIC	LDO     RR'__iob-$global$+32(%r1),%r26  ;offset 0xa28
-        ;--- not PIC	.CALL   ARGW0=GR,ARGW1=GR,ARGW2=GR,RTNVAL=GR    ;in=24,25,26;out=28;
-        ;--- not PIC	B,L     fprintf,%r2     ;offset 0xa2c
-        ;--- not PIC	LDO     RR'C$7(%r21),%r25       ;offset 0xa30
-        .CALL           ;
-        B,L     abort,%r2       ;offset 0xa34
-        NOP             ;offset 0xa38
-        B       $D3     ;offset 0xa3c
-        LDW     -212(%r30),%r2  ;offset 0xa40
-$00060020
-        COPY    %r4,%r26        ;offset 0xa44
-        EXTRD,U %r4,31,32,%r25  ;offset 0xa48
-        COPY    %r2,%r24        ;offset 0xa4c
-        .CALL   ;in=23,24,25,26;out=20,21,22,28,29; (MILLICALL)
-        B,L     $$div2U,%r31    ;offset 0xa50
-        EXTRD,U %r2,31,32,%r23  ;offset 0xa54
-        DEPD    %r28,31,32,%r29 ;offset 0xa58
-$00060022
-        STD     %r29,-152(%r30) ;offset 0xa5c
-$D1
-        AND     %r5,%r19,%r24   ;offset 0xa60
-        EXTRD,U %r24,31,32,%r24 ;offset 0xa64
-        STW     %r2,-160(%r30)  ;offset 0xa68
-        STW     %r7,-128(%r30)  ;offset 0xa6c
-        FLDD    -152(%r30),%fr4 ;offset 0xa70
-        FLDD    -152(%r30),%fr7 ;offset 0xa74
-        FLDW    -160(%r30),%fr8L        ;offset 0xa78
-        FLDW    -128(%r30),%fr5L        ;offset 0xa7c
-        XMPYU   %fr8L,%fr7L,%fr10       ;offset 0xa80
-        FSTD    %fr10,-136(%r30)        ;offset 0xa84
-        XMPYU   %fr8L,%fr7R,%fr22       ;offset 0xa88
-        FSTD    %fr22,-144(%r30)        ;offset 0xa8c
-        XMPYU   %fr5L,%fr4L,%fr11       ;offset 0xa90
-        XMPYU   %fr5L,%fr4R,%fr23       ;offset 0xa94
-        FSTD    %fr11,-112(%r30)        ;offset 0xa98
-        FSTD    %fr23,-120(%r30)        ;offset 0xa9c
-        LDD     -136(%r30),%r28 ;offset 0xaa0
-        DEPD,Z  %r28,31,32,%r31 ;offset 0xaa4
-        LDD     -144(%r30),%r20 ;offset 0xaa8
-        ADD,L   %r20,%r31,%r31  ;offset 0xaac
-        LDD     -112(%r30),%r22 ;offset 0xab0
-        DEPD,Z  %r22,31,32,%r22 ;offset 0xab4
-        LDD     -120(%r30),%r21 ;offset 0xab8
-        B       $00060024       ;offset 0xabc
-        ADD,L   %r21,%r22,%r23  ;offset 0xac0
-$D0
-        OR      %r9,%r29,%r29   ;offset 0xac4
-$00060040
-        EXTRD,U %r29,31,32,%r28 ;offset 0xac8
-$00060002
-$L2
-        LDW     -212(%r30),%r2  ;offset 0xacc
-$D3
-        LDW     -168(%r30),%r9  ;offset 0xad0
-        LDD     -176(%r30),%r8  ;offset 0xad4
-        EXTRD,U %r8,31,32,%r7   ;offset 0xad8
-        LDD     -184(%r30),%r6  ;offset 0xadc
-        EXTRD,U %r6,31,32,%r5   ;offset 0xae0
-        LDW     -188(%r30),%r4  ;offset 0xae4
-        BVE     (%r2)   ;offset 0xae8
-        .EXIT
-        LDW,MB  -192(%r30),%r3  ;offset 0xaec
-	.PROCEND	;in=23,25;out=28,29;fpin=105,107;
-
-
-
-
-;----------------------------------------------------------------------------
-;
-; Registers to hold 64-bit values to manipulate.  The "L" part
-; of the register corresponds to the upper 32-bits, while the "R"
-; part corresponds to the lower 32-bits
-; 
-; Note, that when using b6 and b7, the code must save these before
-; using them because they are callee save registers 
-; 
-;
-; Floating point registers to use to save values that
-; are manipulated.  These don't collide with ftemp1-6 and
-; are all caller save registers
-;
-a0        .reg %fr22
-a0L       .reg %fr22L
-a0R       .reg %fr22R
-
-a1        .reg %fr23
-a1L       .reg %fr23L
-a1R       .reg %fr23R
-
-a2        .reg %fr24
-a2L       .reg %fr24L
-a2R       .reg %fr24R
-
-a3        .reg %fr25
-a3L       .reg %fr25L
-a3R       .reg %fr25R
-
-a4        .reg %fr26
-a4L       .reg %fr26L
-a4R       .reg %fr26R
-
-a5        .reg %fr27
-a5L       .reg %fr27L
-a5R       .reg %fr27R
-
-a6        .reg %fr28
-a6L       .reg %fr28L
-a6R       .reg %fr28R
-
-a7        .reg %fr29
-a7L       .reg %fr29L
-a7R       .reg %fr29R
-
-b0        .reg %fr30
-b0L       .reg %fr30L
-b0R       .reg %fr30R
-
-b1        .reg %fr31
-b1L       .reg %fr31L
-b1R       .reg %fr31R
-
-;
-; Temporary floating point variables, these are all caller save
-; registers
-;
-ftemp1    .reg %fr4
-ftemp2    .reg %fr5
-ftemp3    .reg %fr6
-ftemp4    .reg %fr7
-
-;
-; The B set of registers when used.
-;
-
-b2        .reg %fr8
-b2L       .reg %fr8L
-b2R       .reg %fr8R
-
-b3        .reg %fr9
-b3L       .reg %fr9L
-b3R       .reg %fr9R
-
-b4        .reg %fr10
-b4L       .reg %fr10L
-b4R       .reg %fr10R
-
-b5        .reg %fr11
-b5L       .reg %fr11L
-b5R       .reg %fr11R
-
-b6        .reg %fr12
-b6L       .reg %fr12L
-b6R       .reg %fr12R
-
-b7        .reg %fr13
-b7L       .reg %fr13L
-b7R       .reg %fr13R
-
-c1           .reg %r21   ; only reg
-temp1        .reg %r20   ; only reg
-temp2        .reg %r19   ; only reg
-temp3        .reg %r31   ; only reg
-
-m1           .reg %r28   
-c2           .reg %r23   
-high_one     .reg %r1
-ht           .reg %r6
-lt           .reg %r5
-m            .reg %r4
-c3           .reg %r3
-
-SQR_ADD_C  .macro  A0L,A0R,C1,C2,C3
-    XMPYU   A0L,A0R,ftemp1       ; m
-    FSTD    ftemp1,-24(%sp)      ; store m
-
-    XMPYU   A0R,A0R,ftemp2       ; lt
-    FSTD    ftemp2,-16(%sp)      ; store lt
-
-    XMPYU   A0L,A0L,ftemp3       ; ht
-    FSTD    ftemp3,-8(%sp)       ; store ht
-
-    LDD     -24(%sp),m           ; load m
-    AND     m,high_mask,temp2    ; m & Mask
-    DEPD,Z  m,30,31,temp3        ; m << 32+1
-    LDD     -16(%sp),lt          ; lt
-
-    LDD     -8(%sp),ht           ; ht
-    EXTRD,U temp2,32,33,temp1    ; temp1 = m&Mask >> 32-1
-    ADD     temp3,lt,lt          ; lt = lt+m
-    ADD,L   ht,temp1,ht          ; ht += temp1
-    ADD,DC  ht,%r0,ht            ; ht++
-
-    ADD     C1,lt,C1             ; c1=c1+lt
-    ADD,DC  ht,%r0,ht            ; ht++
-
-    ADD     C2,ht,C2             ; c2=c2+ht
-    ADD,DC  C3,%r0,C3            ; c3++
-.endm
-
-SQR_ADD_C2 .macro  A0L,A0R,A1L,A1R,C1,C2,C3
-    XMPYU   A0L,A1R,ftemp1          ; m1 = bl*ht
-    FSTD    ftemp1,-16(%sp)         ;
-    XMPYU   A0R,A1L,ftemp2          ; m = bh*lt
-    FSTD    ftemp2,-8(%sp)          ;
-    XMPYU   A0R,A1R,ftemp3          ; lt = bl*lt
-    FSTD    ftemp3,-32(%sp)
-    XMPYU   A0L,A1L,ftemp4          ; ht = bh*ht
-    FSTD    ftemp4,-24(%sp)         ;
-
-    LDD     -8(%sp),m               ; r21 = m
-    LDD     -16(%sp),m1             ; r19 = m1
-    ADD,L   m,m1,m                  ; m+m1
-
-    DEPD,Z  m,31,32,temp3           ; (m+m1<<32)
-    LDD     -24(%sp),ht             ; r24 = ht
-
-    CMPCLR,*>>= m,m1,%r0            ; if (m < m1)
-    ADD,L   ht,high_one,ht          ; ht+=high_one
-
-    EXTRD,U m,31,32,temp1           ; m >> 32
-    LDD     -32(%sp),lt             ; lt
-    ADD,L   ht,temp1,ht             ; ht+= m>>32
-    ADD     lt,temp3,lt             ; lt = lt+m1
-    ADD,DC  ht,%r0,ht               ; ht++
-
-    ADD     ht,ht,ht                ; ht=ht+ht;
-    ADD,DC  C3,%r0,C3               ; add in carry (c3++)
-
-    ADD     lt,lt,lt                ; lt=lt+lt;
-    ADD,DC  ht,%r0,ht               ; add in carry (ht++)
-
-    ADD     C1,lt,C1                ; c1=c1+lt
-    ADD,DC,*NUV ht,%r0,ht           ; add in carry (ht++)
-    LDO     1(C3),C3              ; bump c3 if overflow,nullify otherwise
-
-    ADD     C2,ht,C2                ; c2 = c2 + ht
-    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
-.endm
-
-;
-;void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
-; arg0 = r_ptr
-; arg1 = a_ptr
-;
-
-bn_sqr_comba8
-	.PROC
-	.CALLINFO FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .ENTRY
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD     0(a_ptr),a0       
-    FLDD     8(a_ptr),a1       
-    FLDD    16(a_ptr),a2       
-    FLDD    24(a_ptr),a3       
-    FLDD    32(a_ptr),a4       
-    FLDD    40(a_ptr),a5       
-    FLDD    48(a_ptr),a6       
-    FLDD    56(a_ptr),a7       
-
-	SQR_ADD_C a0L,a0R,c1,c2,c3
-	STD     c1,0(r_ptr)          ; r[0] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
-	STD     c2,8(r_ptr)          ; r[1] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
-	STD     c3,16(r_ptr)            ; r[2] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
-	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
-	STD     c1,24(r_ptr)           ; r[3] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
-	SQR_ADD_C2 a4L,a4R,a0L,a0R,c2,c3,c1
-	STD     c2,32(r_ptr)          ; r[4] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a5L,a5R,a0L,a0R,c3,c1,c2
-	SQR_ADD_C2 a4L,a4R,a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
-	STD     c3,40(r_ptr)          ; r[5] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C a3L,a3R,c1,c2,c3
-	SQR_ADD_C2 a4L,a4R,a2L,a2R,c1,c2,c3
-	SQR_ADD_C2 a5L,a5R,a1L,a1R,c1,c2,c3
-	SQR_ADD_C2 a6L,a6R,a0L,a0R,c1,c2,c3
-	STD     c1,48(r_ptr)          ; r[6] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a7L,a7R,a0L,a0R,c2,c3,c1
-	SQR_ADD_C2 a6L,a6R,a1L,a1R,c2,c3,c1
-	SQR_ADD_C2 a5L,a5R,a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a4L,a4R,a3L,a3R,c2,c3,c1
-	STD     c2,56(r_ptr)          ; r[7] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a4L,a4R,c3,c1,c2
-	SQR_ADD_C2 a5L,a5R,a3L,a3R,c3,c1,c2
-	SQR_ADD_C2 a6L,a6R,a2L,a2R,c3,c1,c2
-	SQR_ADD_C2 a7L,a7R,a1L,a1R,c3,c1,c2
-	STD     c3,64(r_ptr)          ; r[8] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a7L,a7R,a2L,a2R,c1,c2,c3
-	SQR_ADD_C2 a6L,a6R,a3L,a3R,c1,c2,c3
-	SQR_ADD_C2 a5L,a5R,a4L,a4R,c1,c2,c3
-	STD     c1,72(r_ptr)          ; r[9] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a5L,a5R,c2,c3,c1
-	SQR_ADD_C2 a6L,a6R,a4L,a4R,c2,c3,c1
-	SQR_ADD_C2 a7L,a7R,a3L,a3R,c2,c3,c1
-	STD     c2,80(r_ptr)          ; r[10] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a7L,a7R,a4L,a4R,c3,c1,c2
-	SQR_ADD_C2 a6L,a6R,a5L,a5R,c3,c1,c2
-	STD     c3,88(r_ptr)          ; r[11] = c3;
-	COPY    %r0,c3
-	
-	SQR_ADD_C a6L,a6R,c1,c2,c3
-	SQR_ADD_C2 a7L,a7R,a5L,a5R,c1,c2,c3
-	STD     c1,96(r_ptr)          ; r[12] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a7L,a7R,a6L,a6R,c2,c3,c1
-	STD     c2,104(r_ptr)         ; r[13] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a7L,a7R,c3,c1,c2
-	STD     c3, 112(r_ptr)       ; r[14] = c3
-	STD     c1, 120(r_ptr)       ; r[15] = c1
-
-    .EXIT
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-;-----------------------------------------------------------------------------
-;
-;void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
-; arg0 = r_ptr
-; arg1 = a_ptr
-;
-
-bn_sqr_comba4
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD     0(a_ptr),a0       
-    FLDD     8(a_ptr),a1       
-    FLDD    16(a_ptr),a2       
-    FLDD    24(a_ptr),a3       
-    FLDD    32(a_ptr),a4       
-    FLDD    40(a_ptr),a5       
-    FLDD    48(a_ptr),a6       
-    FLDD    56(a_ptr),a7       
-
-	SQR_ADD_C a0L,a0R,c1,c2,c3
-
-	STD     c1,0(r_ptr)          ; r[0] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
-
-	STD     c2,8(r_ptr)          ; r[1] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
-
-	STD     c3,16(r_ptr)            ; r[2] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
-	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
-
-	STD     c1,24(r_ptr)           ; r[3] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
-
-	STD     c2,32(r_ptr)           ; r[4] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
-	STD     c3,40(r_ptr)           ; r[5] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C a3L,a3R,c1,c2,c3
-	STD     c1,48(r_ptr)           ; r[6] = c1;
-	STD     c2,56(r_ptr)           ; r[7] = c2;
-
-    .EXIT
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-
-;---------------------------------------------------------------------------
-
-MUL_ADD_C  .macro  A0L,A0R,B0L,B0R,C1,C2,C3
-    XMPYU   A0L,B0R,ftemp1        ; m1 = bl*ht
-    FSTD    ftemp1,-16(%sp)       ;
-    XMPYU   A0R,B0L,ftemp2        ; m = bh*lt
-    FSTD    ftemp2,-8(%sp)        ;
-    XMPYU   A0R,B0R,ftemp3        ; lt = bl*lt
-    FSTD    ftemp3,-32(%sp)
-    XMPYU   A0L,B0L,ftemp4        ; ht = bh*ht
-    FSTD    ftemp4,-24(%sp)       ;
-
-    LDD     -8(%sp),m             ; r21 = m
-    LDD     -16(%sp),m1           ; r19 = m1
-    ADD,L   m,m1,m                ; m+m1
-
-    DEPD,Z  m,31,32,temp3         ; (m+m1<<32)
-    LDD     -24(%sp),ht           ; r24 = ht
-
-    CMPCLR,*>>= m,m1,%r0          ; if (m < m1)
-    ADD,L   ht,high_one,ht        ; ht+=high_one
-
-    EXTRD,U m,31,32,temp1         ; m >> 32
-    LDD     -32(%sp),lt           ; lt
-    ADD,L   ht,temp1,ht           ; ht+= m>>32
-    ADD     lt,temp3,lt           ; lt = lt+m1
-    ADD,DC  ht,%r0,ht             ; ht++
-
-    ADD     C1,lt,C1              ; c1=c1+lt
-    ADD,DC  ht,%r0,ht             ; bump c3 if overflow,nullify otherwise
-
-    ADD     C2,ht,C2              ; c2 = c2 + ht
-    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
-.endm
-
-
-;
-;void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg2 = b_ptr
-;
-
-bn_mul_comba8
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_mul_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-    FSTD    %fr12,32(%sp)       ; save r6
-    FSTD    %fr13,40(%sp)       ; save r7
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD      0(a_ptr),a0       
-    FLDD      8(a_ptr),a1       
-    FLDD     16(a_ptr),a2       
-    FLDD     24(a_ptr),a3       
-    FLDD     32(a_ptr),a4       
-    FLDD     40(a_ptr),a5       
-    FLDD     48(a_ptr),a6       
-    FLDD     56(a_ptr),a7       
-
-    FLDD      0(b_ptr),b0       
-    FLDD      8(b_ptr),b1       
-    FLDD     16(b_ptr),b2       
-    FLDD     24(b_ptr),b3       
-    FLDD     32(b_ptr),b4       
-    FLDD     40(b_ptr),b5       
-    FLDD     48(b_ptr),b6       
-    FLDD     56(b_ptr),b7       
-
-	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
-	STD       c1,0(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
-	STD       c2,8(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
-	STD       c3,16(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
-	STD       c1,24(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a4L,a4R,b0L,b0R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a0L,a0R,b4L,b4R,c2,c3,c1
-	STD       c2,32(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a0L,a0R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b4L,b4R,c3,c1,c2
-	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
-	MUL_ADD_C a4L,a4R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b0L,b0R,c3,c1,c2
-	STD       c3,40(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a6L,a6R,b0L,b0R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a4L,a4R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b4L,b4R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a0L,a0R,b6L,b6R,c1,c2,c3
-	STD       c1,48(r_ptr)
-	COPY      %r0,c1
-	
-	MUL_ADD_C a0L,a0R,b7L,b7R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b6L,b6R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b5L,b5R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b4L,b4R,c2,c3,c1
-	MUL_ADD_C a4L,a4R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a5L,a5R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a6L,a6R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a7L,a7R,b0L,b0R,c2,c3,c1
-	STD       c2,56(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a7L,a7R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a6L,a6R,b2L,b2R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a4L,a4R,b4L,b4R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a2L,a2R,b6L,b6R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b7L,b7R,c3,c1,c2
-	STD       c3,64(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a2L,a2R,b7L,b7R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b6L,b6R,c1,c2,c3
-	MUL_ADD_C a4L,a4R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b4L,b4R,c1,c2,c3
-	MUL_ADD_C a6L,a6R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a7L,a7R,b2L,b2R,c1,c2,c3
-	STD       c1,72(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a7L,a7R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a6L,a6R,b4L,b4R,c2,c3,c1
-	MUL_ADD_C a5L,a5R,b5L,b5R,c2,c3,c1
-	MUL_ADD_C a4L,a4R,b6L,b6R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b7L,b7R,c2,c3,c1
-	STD       c2,80(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a4L,a4R,b7L,b7R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b6L,b6R,c3,c1,c2
-	MUL_ADD_C a6L,a6R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a7L,a7R,b4L,b4R,c3,c1,c2
-	STD       c3,88(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a7L,a7R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a6L,a6R,b6L,b6R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b7L,b7R,c1,c2,c3
-	STD       c1,96(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a6L,a6R,b7L,b7R,c2,c3,c1
-	MUL_ADD_C a7L,a7R,b6L,b6R,c2,c3,c1
-	STD       c2,104(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a7L,a7R,b7L,b7R,c3,c1,c2
-	STD       c3,112(r_ptr)
-	STD       c1,120(r_ptr)
-
-    .EXIT
-    FLDD    -88(%sp),%fr13 
-    FLDD    -96(%sp),%fr12 
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-;-----------------------------------------------------------------------------
-;
-;void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg2 = b_ptr
-;
-
-bn_mul_comba4
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_mul_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-    FSTD    %fr12,32(%sp)       ; save r6
-    FSTD    %fr13,40(%sp)       ; save r7
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD      0(a_ptr),a0       
-    FLDD      8(a_ptr),a1       
-    FLDD     16(a_ptr),a2       
-    FLDD     24(a_ptr),a3       
-
-    FLDD      0(b_ptr),b0       
-    FLDD      8(b_ptr),b1       
-    FLDD     16(b_ptr),b2       
-    FLDD     24(b_ptr),b3       
-
-	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
-	STD       c1,0(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
-	STD       c2,8(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
-	STD       c3,16(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
-	STD       c1,24(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
-	STD       c2,32(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
-	STD       c3,40(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
-	STD       c1,48(r_ptr)
-	STD       c2,56(r_ptr)
-
-    .EXIT
-    FLDD    -88(%sp),%fr13 
-    FLDD    -96(%sp),%fr12 
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-
-;--- not PIC	.SPACE	$TEXT$
-;--- not PIC	.SUBSPA	$CODE$
-;--- not PIC	.SPACE	$PRIVATE$,SORT=16
-;--- not PIC	.IMPORT	$global$,DATA
-;--- not PIC	.SPACE	$TEXT$
-;--- not PIC	.SUBSPA	$CODE$
-;--- not PIC	.SUBSPA	$LIT$,ACCESS=0x2c
-;--- not PIC	C$7
-;--- not PIC	.ALIGN	8
-;--- not PIC	.STRINGZ	"Division would overflow (%d)\n"
-	.END
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2W.S b/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2W.S
deleted file mode 100644
index a995457..0000000
--- a/src/third_party/openssl/openssl/crypto/bn/asm/pa-risc2W.S
+++ /dev/null
@@ -1,1605 +0,0 @@
-;
-; PA-RISC 64-bit implementation of bn_asm code
-;
-; This code is approximately 2x faster than the C version
-; for RSA/DSA.
-;
-; See http://devresource.hp.com/  for more details on the PA-RISC
-; architecture.  Also see the book "PA-RISC 2.0 Architecture"
-; by Gerry Kane for information on the instruction set architecture.
-;
-; Code written by Chris Ruemmler (with some help from the HP C
-; compiler).
-;
-; The code compiles with HP's assembler
-;
-
-	.level	2.0W
-	.space	$TEXT$
-	.subspa	$CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY
-
-;
-; Global Register definitions used for the routines.
-;
-; Some information about HP's runtime architecture for 64-bits.
-;
-; "Caller save" means the calling function must save the register
-; if it wants the register to be preserved.
-; "Callee save" means if a function uses the register, it must save
-; the value before using it.
-;
-; For the floating point registers 
-;
-;    "caller save" registers: fr4-fr11, fr22-fr31
-;    "callee save" registers: fr12-fr21
-;    "special" registers: fr0-fr3 (status and exception registers)
-;
-; For the integer registers
-;     value zero             :  r0
-;     "caller save" registers: r1,r19-r26
-;     "callee save" registers: r3-r18
-;     return register        :  r2  (rp)
-;     return values          ; r28  (ret0,ret1)
-;     Stack pointer          ; r30  (sp) 
-;     global data pointer    ; r27  (dp)
-;     argument pointer       ; r29  (ap)
-;     millicode return ptr   ; r31  (also a caller save register)
-
-
-;
-; Arguments to the routines
-;
-r_ptr       .reg %r26
-a_ptr       .reg %r25
-b_ptr       .reg %r24
-num         .reg %r24
-w           .reg %r23
-n           .reg %r23
-
-
-;
-; Globals used in some routines
-;
-
-top_overflow .reg %r29
-high_mask    .reg %r22    ; value 0xffffffff80000000L
-
-
-;------------------------------------------------------------------------------
-;
-; bn_mul_add_words
-;
-;BN_ULONG bn_mul_add_words(BN_ULONG *r_ptr, BN_ULONG *a_ptr, 
-;								int num, BN_ULONG w)
-;
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg2 = num
-; arg3 = w
-;
-; Local register definitions
-;
-
-fm1          .reg %fr22
-fm           .reg %fr23
-ht_temp      .reg %fr24
-ht_temp_1    .reg %fr25
-lt_temp      .reg %fr26
-lt_temp_1    .reg %fr27
-fm1_1        .reg %fr28
-fm_1         .reg %fr29
-
-fw_h         .reg %fr7L
-fw_l         .reg %fr7R
-fw           .reg %fr7
-
-fht_0        .reg %fr8L
-flt_0        .reg %fr8R
-t_float_0    .reg %fr8
-
-fht_1        .reg %fr9L
-flt_1        .reg %fr9R
-t_float_1    .reg %fr9
-
-tmp_0        .reg %r31
-tmp_1        .reg %r21
-m_0          .reg %r20 
-m_1          .reg %r19 
-ht_0         .reg %r1  
-ht_1         .reg %r3
-lt_0         .reg %r4
-lt_1         .reg %r5
-m1_0         .reg %r6 
-m1_1         .reg %r7 
-rp_val       .reg %r8
-rp_val_1     .reg %r9
-
-bn_mul_add_words
-	.export	bn_mul_add_words,entry,NO_RELOCATION,LONG_RETURN
-	.proc
-	.callinfo frame=128
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-	NOP                         ; Needed to make the loop 16-byte aligned
-	NOP                         ; Needed to make the loop 16-byte aligned
-
-    STD     %r5,16(%sp)         ; save r5  
-    STD     %r6,24(%sp)         ; save r6  
-    STD     %r7,32(%sp)         ; save r7  
-    STD     %r8,40(%sp)         ; save r8  
-
-    STD     %r9,48(%sp)         ; save r9  
-    COPY    %r0,%ret0           ; return 0 by default
-    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
-	STD     w,56(%sp)           ; store w on stack
-
-    CMPIB,>= 0,num,bn_mul_add_words_exit  ; if (num <= 0) then exit
-	LDO     128(%sp),%sp       ; bump stack
-
-	;
-	; The loop is unrolled twice, so if there is only 1 number
-    ; then go straight to the cleanup code.
-	;
-	CMPIB,= 1,num,bn_mul_add_words_single_top
-	FLDD    -72(%sp),fw     ; load up w into fp register fw (fw_h/fw_l)
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
-    ; two 32-bit mutiplies can be issued per cycle.
-    ; 
-bn_mul_add_words_unroll2
-
-    FLDD    0(a_ptr),t_float_0       ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    FLDD    8(a_ptr),t_float_1       ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    LDD     0(r_ptr),rp_val          ; rp[0]
-    LDD     8(r_ptr),rp_val_1        ; rp[1]
-
-    XMPYU   fht_0,fw_l,fm1           ; m1[0] = fht_0*fw_l
-    XMPYU   fht_1,fw_l,fm1_1         ; m1[1] = fht_1*fw_l
-    FSTD    fm1,-16(%sp)             ; -16(sp) = m1[0]
-    FSTD    fm1_1,-48(%sp)           ; -48(sp) = m1[1]
-
-    XMPYU   flt_0,fw_h,fm            ; m[0] = flt_0*fw_h
-    XMPYU   flt_1,fw_h,fm_1          ; m[1] = flt_1*fw_h
-    FSTD    fm,-8(%sp)               ; -8(sp) = m[0]
-    FSTD    fm_1,-40(%sp)            ; -40(sp) = m[1]
-
-    XMPYU   fht_0,fw_h,ht_temp       ; ht_temp   = fht_0*fw_h
-    XMPYU   fht_1,fw_h,ht_temp_1     ; ht_temp_1 = fht_1*fw_h
-    FSTD    ht_temp,-24(%sp)         ; -24(sp)   = ht_temp
-    FSTD    ht_temp_1,-56(%sp)       ; -56(sp)   = ht_temp_1
-
-    XMPYU   flt_0,fw_l,lt_temp       ; lt_temp = lt*fw_l
-    XMPYU   flt_1,fw_l,lt_temp_1     ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)         ; -32(sp) = lt_temp 
-    FSTD    lt_temp_1,-64(%sp)       ; -64(sp) = lt_temp_1 
-
-    LDD     -8(%sp),m_0              ; m[0] 
-    LDD     -40(%sp),m_1             ; m[1]
-    LDD     -16(%sp),m1_0            ; m1[0]
-    LDD     -48(%sp),m1_1            ; m1[1]
-
-    LDD     -24(%sp),ht_0            ; ht[0]
-    LDD     -56(%sp),ht_1            ; ht[1]
-    ADD,L   m1_0,m_0,tmp_0           ; tmp_0 = m[0] + m1[0]; 
-    ADD,L   m1_1,m_1,tmp_1           ; tmp_1 = m[1] + m1[1]; 
-
-    LDD     -32(%sp),lt_0            
-    LDD     -64(%sp),lt_1            
-    CMPCLR,*>>= tmp_0,m1_0, %r0      ; if (m[0] < m1[0])
-    ADD,L   ht_0,top_overflow,ht_0   ; ht[0] += (1<<32)
-
-    CMPCLR,*>>= tmp_1,m1_1,%r0       ; if (m[1] < m1[1])
-    ADD,L   ht_1,top_overflow,ht_1   ; ht[1] += (1<<32)
-    EXTRD,U tmp_0,31,32,m_0          ; m[0]>>32  
-    DEPD,Z  tmp_0,31,32,m1_0         ; m1[0] = m[0]<<32 
-
-    EXTRD,U tmp_1,31,32,m_1          ; m[1]>>32  
-    DEPD,Z  tmp_1,31,32,m1_1         ; m1[1] = m[1]<<32 
-    ADD,L   ht_0,m_0,ht_0            ; ht[0]+= (m[0]>>32)
-    ADD,L   ht_1,m_1,ht_1            ; ht[1]+= (m[1]>>32)
-
-    ADD     lt_0,m1_0,lt_0           ; lt[0] = lt[0]+m1[0];
-	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-    ADD     lt_1,m1_1,lt_1           ; lt[1] = lt[1]+m1[1];
-    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
-
-    ADD    %ret0,lt_0,lt_0           ; lt[0] = lt[0] + c;
-	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-    ADD     lt_0,rp_val,lt_0         ; lt[0] = lt[0]+rp[0]
-    ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
-
-	LDO    -2(num),num               ; num = num - 2;
-    ADD     ht_0,lt_1,lt_1           ; lt[1] = lt[1] + ht_0 (c);
-    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
-    STD     lt_0,0(r_ptr)            ; rp[0] = lt[0]
-
-    ADD     lt_1,rp_val_1,lt_1       ; lt[1] = lt[1]+rp[1]
-    ADD,DC  ht_1,%r0,%ret0           ; ht[1]++
-    LDO     16(a_ptr),a_ptr          ; a_ptr += 2
-
-    STD     lt_1,8(r_ptr)            ; rp[1] = lt[1]
-	CMPIB,<= 2,num,bn_mul_add_words_unroll2 ; go again if more to do
-    LDO     16(r_ptr),r_ptr          ; r_ptr += 2
-
-    CMPIB,=,N 0,num,bn_mul_add_words_exit ; are we done, or cleanup last one
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_mul_add_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    LDD     0(r_ptr),rp_val           ; rp[0]
-    LDO     8(a_ptr),a_ptr            ; a_ptr++
-    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-
-    LDD     -8(%sp),m_0               
-    LDD    -16(%sp),m1_0              ; m1 = temp1 
-    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
-    LDD     -24(%sp),ht_0             
-    LDD     -32(%sp),lt_0             
-
-    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,tmp_0           ; tmp_0 = lt+m1;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-    ADD     %ret0,tmp_0,lt_0          ; lt = lt + c;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-    ADD     lt_0,rp_val,lt_0          ; lt = lt+rp[0]
-    ADD,DC  ht_0,%r0,%ret0            ; ht++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-
-bn_mul_add_words_exit
-    .EXIT
-    LDD     -80(%sp),%r9              ; restore r9  
-    LDD     -88(%sp),%r8              ; restore r8  
-    LDD     -96(%sp),%r7              ; restore r7  
-    LDD     -104(%sp),%r6             ; restore r6  
-    LDD     -112(%sp),%r5             ; restore r5  
-    LDD     -120(%sp),%r4             ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3             ; restore r3
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
-;
-; arg0 = rp
-; arg1 = ap
-; arg2 = num
-; arg3 = w
-
-bn_mul_words
-	.proc
-	.callinfo frame=128
-    .entry
-	.EXPORT	bn_mul_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-    STD     %r5,16(%sp)         ; save r5  
-    STD     %r6,24(%sp)         ; save r6  
-
-    STD     %r7,32(%sp)         ; save r7  
-    COPY    %r0,%ret0           ; return 0 by default
-    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
-	STD     w,56(%sp)           ; w on stack
-
-    CMPIB,>= 0,num,bn_mul_words_exit
-	LDO     128(%sp),%sp       ; bump stack
-
-	;
-	; See if only 1 word to do, thus just do cleanup
-	;
-	CMPIB,= 1,num,bn_mul_words_single_top
-	FLDD    -72(%sp),fw     ; load up w into fp register fw (fw_h/fw_l)
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
-    ; two 32-bit mutiplies can be issued per cycle.
-    ; 
-bn_mul_words_unroll2
-
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    FLDD    8(a_ptr),t_float_1        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-    XMPYU   fht_0,fw_l,fm1            ; m1[0] = fht_0*fw_l
-    XMPYU   fht_1,fw_l,fm1_1          ; m1[1] = ht*fw_l
-
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    FSTD    fm1_1,-48(%sp)            ; -48(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    XMPYU   flt_1,fw_h,fm_1           ; m = lt*fw_h
-
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    FSTD    fm_1,-40(%sp)             ; -40(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = fht_0*fw_h
-    XMPYU   fht_1,fw_h,ht_temp_1      ; ht_temp = ht*fw_h
-
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    FSTD    ht_temp_1,-56(%sp)        ; -56(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    XMPYU   flt_1,fw_l,lt_temp_1      ; lt_temp = lt*fw_l
-
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-    FSTD    lt_temp_1,-64(%sp)        ; -64(sp) = lt 
-    LDD     -8(%sp),m_0               
-    LDD     -40(%sp),m_1              
-
-    LDD    -16(%sp),m1_0              
-    LDD    -48(%sp),m1_1              
-    LDD     -24(%sp),ht_0             
-    LDD     -56(%sp),ht_1             
-
-    ADD,L   m1_0,m_0,tmp_0            ; tmp_0 = m + m1; 
-    ADD,L   m1_1,m_1,tmp_1            ; tmp_1 = m + m1; 
-    LDD     -32(%sp),lt_0             
-    LDD     -64(%sp),lt_1             
-
-    CMPCLR,*>>= tmp_0,m1_0, %r0       ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-    CMPCLR,*>>= tmp_1,m1_1,%r0        ; if (m < m1)
-    ADD,L   ht_1,top_overflow,ht_1    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-    EXTRD,U tmp_1,31,32,m_1           ; m>>32  
-    DEPD,Z  tmp_1,31,32,m1_1          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD,L   ht_1,m_1,ht_1             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,lt_0            ; lt = lt+m1;
-	ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     lt_1,m1_1,lt_1            ; lt = lt+m1;
-    ADD,DC  ht_1,%r0,ht_1             ; ht++
-    ADD    %ret0,lt_0,lt_0            ; lt = lt + c (ret0);
-	ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     ht_0,lt_1,lt_1            ; lt = lt + c (ht_0)
-    ADD,DC  ht_1,%r0,ht_1             ; ht++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-    STD     lt_1,8(r_ptr)             ; rp[1] = lt
-
-	COPY    ht_1,%ret0                ; carry = ht
-	LDO    -2(num),num                ; num = num - 2;
-    LDO     16(a_ptr),a_ptr           ; ap += 2
-	CMPIB,<= 2,num,bn_mul_words_unroll2
-    LDO     16(r_ptr),r_ptr           ; rp++
-
-    CMPIB,=,N 0,num,bn_mul_words_exit ; are we done?
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_mul_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-
-    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
-    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
-    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
-    FSTD    fm,-8(%sp)                ; -8(sp) = m
-    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
-    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
-    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
-    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
-
-    LDD     -8(%sp),m_0               
-    LDD    -16(%sp),m1_0              
-    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
-    LDD     -24(%sp),ht_0             
-    LDD     -32(%sp),lt_0             
-
-    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
-    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
-
-    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
-    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
-
-    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
-    ADD     lt_0,m1_0,lt_0            ; lt= lt+m1;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    ADD     %ret0,lt_0,lt_0           ; lt = lt + c;
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    COPY    ht_0,%ret0                ; copy carry
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-
-bn_mul_words_exit
-    .EXIT
-    LDD     -96(%sp),%r7              ; restore r7  
-    LDD     -104(%sp),%r6             ; restore r6  
-    LDD     -112(%sp),%r5             ; restore r5  
-    LDD     -120(%sp),%r4             ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3             ; restore r3
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-;void bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num)
-;
-; arg0 = rp
-; arg1 = ap
-; arg2 = num
-;
-
-bn_sqr_words
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3  
-    STD     %r4,8(%sp)          ; save r4  
-	NOP
-    STD     %r5,16(%sp)         ; save r5  
-
-    CMPIB,>= 0,num,bn_sqr_words_exit
-	LDO     128(%sp),%sp       ; bump stack
-
-	;
-	; If only 1, the goto straight to cleanup
-	;
-	CMPIB,= 1,num,bn_sqr_words_single_top
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-
-bn_sqr_words_unroll2
-    FLDD    0(a_ptr),t_float_0        ; a[0]
-    FLDD    8(a_ptr),t_float_1        ; a[1]
-    XMPYU   fht_0,flt_0,fm            ; m[0]
-    XMPYU   fht_1,flt_1,fm_1          ; m[1]
-
-    FSTD    fm,-24(%sp)               ; store m[0]
-    FSTD    fm_1,-56(%sp)             ; store m[1]
-    XMPYU   flt_0,flt_0,lt_temp       ; lt[0]
-    XMPYU   flt_1,flt_1,lt_temp_1     ; lt[1]
-
-    FSTD    lt_temp,-16(%sp)          ; store lt[0]
-    FSTD    lt_temp_1,-48(%sp)        ; store lt[1]
-    XMPYU   fht_0,fht_0,ht_temp       ; ht[0]
-    XMPYU   fht_1,fht_1,ht_temp_1     ; ht[1]
-
-    FSTD    ht_temp,-8(%sp)           ; store ht[0]
-    FSTD    ht_temp_1,-40(%sp)        ; store ht[1]
-    LDD     -24(%sp),m_0             
-    LDD     -56(%sp),m_1              
-
-    AND     m_0,high_mask,tmp_0       ; m[0] & Mask
-    AND     m_1,high_mask,tmp_1       ; m[1] & Mask
-    DEPD,Z  m_0,30,31,m_0             ; m[0] << 32+1
-    DEPD,Z  m_1,30,31,m_1             ; m[1] << 32+1
-
-    LDD     -16(%sp),lt_0        
-    LDD     -48(%sp),lt_1        
-    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m[0]&Mask >> 32-1
-    EXTRD,U tmp_1,32,33,tmp_1         ; tmp_1 = m[1]&Mask >> 32-1
-
-    LDD     -8(%sp),ht_0            
-    LDD     -40(%sp),ht_1           
-    ADD,L   ht_0,tmp_0,ht_0           ; ht[0] += tmp_0
-    ADD,L   ht_1,tmp_1,ht_1           ; ht[1] += tmp_1
-
-    ADD     lt_0,m_0,lt_0             ; lt = lt+m
-    ADD,DC  ht_0,%r0,ht_0             ; ht[0]++
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt[0]
-    STD     ht_0,8(r_ptr)             ; rp[1] = ht[1]
-
-    ADD     lt_1,m_1,lt_1             ; lt = lt+m
-    ADD,DC  ht_1,%r0,ht_1             ; ht[1]++
-    STD     lt_1,16(r_ptr)            ; rp[2] = lt[1]
-    STD     ht_1,24(r_ptr)            ; rp[3] = ht[1]
-
-	LDO    -2(num),num                ; num = num - 2;
-    LDO     16(a_ptr),a_ptr           ; ap += 2
-	CMPIB,<= 2,num,bn_sqr_words_unroll2
-    LDO     32(r_ptr),r_ptr           ; rp += 4
-
-    CMPIB,=,N 0,num,bn_sqr_words_exit ; are we done?
-
-	;
-	; Top of loop aligned on 64-byte boundary
-	;
-bn_sqr_words_single_top
-    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
-
-    XMPYU   fht_0,flt_0,fm            ; m
-    FSTD    fm,-24(%sp)               ; store m
-
-    XMPYU   flt_0,flt_0,lt_temp       ; lt
-    FSTD    lt_temp,-16(%sp)          ; store lt
-
-    XMPYU   fht_0,fht_0,ht_temp       ; ht
-    FSTD    ht_temp,-8(%sp)           ; store ht
-
-    LDD     -24(%sp),m_0              ; load m
-    AND     m_0,high_mask,tmp_0       ; m & Mask
-    DEPD,Z  m_0,30,31,m_0             ; m << 32+1
-    LDD     -16(%sp),lt_0             ; lt
-
-    LDD     -8(%sp),ht_0              ; ht
-    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m&Mask >> 32-1
-    ADD     m_0,lt_0,lt_0             ; lt = lt+m
-    ADD,L   ht_0,tmp_0,ht_0           ; ht += tmp_0
-    ADD,DC  ht_0,%r0,ht_0             ; ht++
-
-    STD     lt_0,0(r_ptr)             ; rp[0] = lt
-    STD     ht_0,8(r_ptr)             ; rp[1] = ht
-
-bn_sqr_words_exit
-    .EXIT
-    LDD     -112(%sp),%r5       ; restore r5  
-    LDD     -120(%sp),%r4       ; restore r4  
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3 
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
-;
-; arg0 = rp 
-; arg1 = ap
-; arg2 = bp 
-; arg3 = n
-
-t  .reg %r22
-b  .reg %r21
-l  .reg %r20
-
-bn_add_words
-	.proc
-    .entry
-	.callinfo
-	.EXPORT	bn_add_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-	.align 64
-
-    CMPIB,>= 0,n,bn_add_words_exit
-    COPY    %r0,%ret0           ; return 0 by default
-
-	;
-	; If 2 or more numbers do the loop
-	;
-	CMPIB,= 1,n,bn_add_words_single_top
-	NOP
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-bn_add_words_unroll2
-	LDD     0(a_ptr),t
-	LDD     0(b_ptr),b
-	ADD     t,%ret0,t                    ; t = t+c;
-	ADD,DC  %r0,%r0,%ret0                ; set c to carry
-	ADD     t,b,l                        ; l = t + b[0]
-	ADD,DC  %ret0,%r0,%ret0              ; c+= carry
-	STD     l,0(r_ptr)
-
-	LDD     8(a_ptr),t
-	LDD     8(b_ptr),b
-	ADD     t,%ret0,t                     ; t = t+c;
-	ADD,DC  %r0,%r0,%ret0                 ; set c to carry
-	ADD     t,b,l                         ; l = t + b[0]
-	ADD,DC  %ret0,%r0,%ret0               ; c+= carry
-	STD     l,8(r_ptr)
-
-	LDO     -2(n),n
-	LDO     16(a_ptr),a_ptr
-	LDO     16(b_ptr),b_ptr
-
-	CMPIB,<= 2,n,bn_add_words_unroll2
-	LDO     16(r_ptr),r_ptr
-
-    CMPIB,=,N 0,n,bn_add_words_exit ; are we done?
-
-bn_add_words_single_top
-	LDD     0(a_ptr),t
-	LDD     0(b_ptr),b
-
-	ADD     t,%ret0,t                 ; t = t+c;
-	ADD,DC  %r0,%r0,%ret0             ; set c to carry (could use CMPCLR??)
-	ADD     t,b,l                     ; l = t + b[0]
-	ADD,DC  %ret0,%r0,%ret0           ; c+= carry
-	STD     l,0(r_ptr)
-
-bn_add_words_exit
-    .EXIT
-    BVE     (%rp)
-	NOP
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-;BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
-;
-; arg0 = rp 
-; arg1 = ap
-; arg2 = bp 
-; arg3 = n
-
-t1       .reg %r22
-t2       .reg %r21
-sub_tmp1 .reg %r20
-sub_tmp2 .reg %r19
-
-
-bn_sub_words
-	.proc
-	.callinfo 
-	.EXPORT	bn_sub_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    CMPIB,>=  0,n,bn_sub_words_exit
-    COPY    %r0,%ret0           ; return 0 by default
-
-	;
-	; If 2 or more numbers do the loop
-	;
-	CMPIB,= 1,n,bn_sub_words_single_top
-	NOP
-
-	;
-	; This loop is unrolled 2 times (64-byte aligned as well)
-	;
-bn_sub_words_unroll2
-	LDD     0(a_ptr),t1
-	LDD     0(b_ptr),t2
-	SUB     t1,t2,sub_tmp1           ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret0,sub_tmp1  ; t3 = t3- c; 
-
-	CMPCLR,*>> t1,t2,sub_tmp2        ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret0
-	STD     sub_tmp1,0(r_ptr)
-
-	LDD     8(a_ptr),t1
-	LDD     8(b_ptr),t2
-	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret0,sub_tmp1   ; t3 = t3- c; 
-	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret0
-	STD     sub_tmp1,8(r_ptr)
-
-	LDO     -2(n),n
-	LDO     16(a_ptr),a_ptr
-	LDO     16(b_ptr),b_ptr
-
-	CMPIB,<= 2,n,bn_sub_words_unroll2
-	LDO     16(r_ptr),r_ptr
-
-    CMPIB,=,N 0,n,bn_sub_words_exit ; are we done?
-
-bn_sub_words_single_top
-	LDD     0(a_ptr),t1
-	LDD     0(b_ptr),t2
-	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
-	SUB     sub_tmp1,%ret0,sub_tmp1   ; t3 = t3- c; 
-	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
-	LDO      1(%r0),sub_tmp2
-	
-	CMPCLR,*= t1,t2,%r0
-	COPY    sub_tmp2,%ret0
-
-	STD     sub_tmp1,0(r_ptr)
-
-bn_sub_words_exit
-    .EXIT
-    BVE     (%rp)
-	NOP
-	.PROCEND	;in=23,24,25,26,29;out=28;
-
-;------------------------------------------------------------------------------
-;
-; unsigned long bn_div_words(unsigned long h, unsigned long l, unsigned long d)
-;
-; arg0 = h
-; arg1 = l
-; arg2 = d
-;
-; This is mainly just modified assembly from the compiler, thus the
-; lack of variable names.
-;
-;------------------------------------------------------------------------------
-bn_div_words
-	.proc
-	.callinfo CALLER,FRAME=272,ENTRY_GR=%r10,SAVE_RP,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_div_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-	.IMPORT	BN_num_bits_word,CODE,NO_RELOCATION
-	.IMPORT	__iob,DATA
-	.IMPORT	fprintf,CODE,NO_RELOCATION
-	.IMPORT	abort,CODE,NO_RELOCATION
-	.IMPORT	$$div2U,MILLICODE
-    .entry
-    STD     %r2,-16(%r30)   
-    STD,MA  %r3,352(%r30)   
-    STD     %r4,-344(%r30)  
-    STD     %r5,-336(%r30)  
-    STD     %r6,-328(%r30)  
-    STD     %r7,-320(%r30)  
-    STD     %r8,-312(%r30)  
-    STD     %r9,-304(%r30)  
-    STD     %r10,-296(%r30)
-
-    STD     %r27,-288(%r30)             ; save gp
-
-    COPY    %r24,%r3           ; save d 
-    COPY    %r26,%r4           ; save h (high 64-bits)
-    LDO      -1(%r0),%ret0     ; return -1 by default	
-
-    CMPB,*=  %r0,%arg2,$D3     ; if (d == 0)
-    COPY    %r25,%r5           ; save l (low 64-bits)
-
-    LDO     -48(%r30),%r29     ; create ap 
-    .CALL   ;in=26,29;out=28;
-    B,L     BN_num_bits_word,%r2 
-    COPY    %r3,%r26        
-    LDD     -288(%r30),%r27    ; restore gp 
-    LDI     64,%r21 
-
-    CMPB,=  %r21,%ret0,$00000012   ;if (i == 64) (forward) 
-    COPY    %ret0,%r24             ; i   
-    MTSARCM %r24    
-    DEPDI,Z -1,%sar,1,%r29  
-    CMPB,*<<,N %r29,%r4,bn_div_err_case ; if (h > 1<<i) (forward) 
-
-$00000012
-    SUBI    64,%r24,%r31                       ; i = 64 - i;
-    CMPCLR,*<< %r4,%r3,%r0                     ; if (h >= d)
-    SUB     %r4,%r3,%r4                        ; h -= d
-    CMPB,=  %r31,%r0,$0000001A                 ; if (i)
-    COPY    %r0,%r10                           ; ret = 0
-    MTSARCM %r31                               ; i to shift
-    DEPD,Z  %r3,%sar,64,%r3                    ; d <<= i;
-    SUBI    64,%r31,%r19                       ; 64 - i; redundent
-    MTSAR   %r19                               ; (64 -i) to shift
-    SHRPD   %r4,%r5,%sar,%r4                   ; l>> (64-i)
-    MTSARCM %r31                               ; i to shift
-    DEPD,Z  %r5,%sar,64,%r5                    ; l <<= i;
-
-$0000001A
-    DEPDI,Z -1,31,32,%r19                      
-    EXTRD,U %r3,31,32,%r6                      ; dh=(d&0xfff)>>32
-    EXTRD,U %r3,63,32,%r8                      ; dl = d&0xffffff
-    LDO     2(%r0),%r9
-    STD    %r3,-280(%r30)                      ; "d" to stack
-
-$0000001C
-    DEPDI,Z -1,63,32,%r29                      ; 
-    EXTRD,U %r4,31,32,%r31                     ; h >> 32
-    CMPB,*=,N  %r31,%r6,$D2     	       ; if ((h>>32) != dh)(forward) div
-    COPY    %r4,%r26       
-    EXTRD,U %r4,31,32,%r25 
-    COPY    %r6,%r24      
-    .CALL   ;in=23,24,25,26;out=20,21,22,28,29; (MILLICALL)
-    B,L     $$div2U,%r2     
-    EXTRD,U %r6,31,32,%r23  
-    DEPD    %r28,31,32,%r29 
-$D2
-    STD     %r29,-272(%r30)                   ; q
-    AND     %r5,%r19,%r24                   ; t & 0xffffffff00000000;
-    EXTRD,U %r24,31,32,%r24                 ; ??? 
-    FLDD    -272(%r30),%fr7                 ; q
-    FLDD    -280(%r30),%fr8                 ; d
-    XMPYU   %fr8L,%fr7L,%fr10  
-    FSTD    %fr10,-256(%r30)   
-    XMPYU   %fr8L,%fr7R,%fr22  
-    FSTD    %fr22,-264(%r30)   
-    XMPYU   %fr8R,%fr7L,%fr11 
-    XMPYU   %fr8R,%fr7R,%fr23
-    FSTD    %fr11,-232(%r30)
-    FSTD    %fr23,-240(%r30)
-    LDD     -256(%r30),%r28
-    DEPD,Z  %r28,31,32,%r2 
-    LDD     -264(%r30),%r20
-    ADD,L   %r20,%r2,%r31   
-    LDD     -232(%r30),%r22 
-    DEPD,Z  %r22,31,32,%r22 
-    LDD     -240(%r30),%r21 
-    B       $00000024       ; enter loop  
-    ADD,L   %r21,%r22,%r23 
-
-$0000002A
-    LDO     -1(%r29),%r29   
-    SUB     %r23,%r8,%r23   
-$00000024
-    SUB     %r4,%r31,%r25   
-    AND     %r25,%r19,%r26  
-    CMPB,*<>,N      %r0,%r26,$00000046  ; (forward)
-    DEPD,Z  %r25,31,32,%r20 
-    OR      %r20,%r24,%r21  
-    CMPB,*<<,N  %r21,%r23,$0000002A ;(backward) 
-    SUB     %r31,%r6,%r31   
-;-------------Break path---------------------
-
-$00000046
-    DEPD,Z  %r23,31,32,%r25              ;tl
-    EXTRD,U %r23,31,32,%r26              ;t
-    AND     %r25,%r19,%r24               ;tl = (tl<<32)&0xfffffff0000000L
-    ADD,L   %r31,%r26,%r31               ;th += t; 
-    CMPCLR,*>>=     %r5,%r24,%r0         ;if (l<tl)
-    LDO     1(%r31),%r31                 ; th++;
-    CMPB,*<<=,N     %r31,%r4,$00000036   ;if (n < th) (forward)
-    LDO     -1(%r29),%r29                ;q--; 
-    ADD,L   %r4,%r3,%r4                  ;h += d;
-$00000036
-    ADDIB,=,N       -1,%r9,$D1 ;if (--count == 0) break (forward) 
-    SUB     %r5,%r24,%r28                ; l -= tl;
-    SUB     %r4,%r31,%r24                ; h -= th;
-    SHRPD   %r24,%r28,32,%r4             ; h = ((h<<32)|(l>>32));
-    DEPD,Z  %r29,31,32,%r10              ; ret = q<<32
-    b      $0000001C
-    DEPD,Z  %r28,31,32,%r5               ; l = l << 32 
-
-$D1
-    OR      %r10,%r29,%r28           ; ret |= q
-$D3
-    LDD     -368(%r30),%r2  
-$D0
-    LDD     -296(%r30),%r10 
-    LDD     -304(%r30),%r9  
-    LDD     -312(%r30),%r8  
-    LDD     -320(%r30),%r7  
-    LDD     -328(%r30),%r6  
-    LDD     -336(%r30),%r5  
-    LDD     -344(%r30),%r4  
-    BVE     (%r2)   
-        .EXIT
-    LDD,MB  -352(%r30),%r3 
-
-bn_div_err_case
-    MFIA    %r6     
-    ADDIL   L'bn_div_words-bn_div_err_case,%r6,%r1 
-    LDO     R'bn_div_words-bn_div_err_case(%r1),%r6  
-    ADDIL   LT'__iob,%r27,%r1       
-    LDD     RT'__iob(%r1),%r26      
-    ADDIL   L'C$4-bn_div_words,%r6,%r1    
-    LDO     R'C$4-bn_div_words(%r1),%r25  
-    LDO     64(%r26),%r26   
-    .CALL           ;in=24,25,26,29;out=28;
-    B,L     fprintf,%r2    
-    LDO     -48(%r30),%r29 
-    LDD     -288(%r30),%r27
-    .CALL           ;in=29;
-    B,L     abort,%r2      
-    LDO     -48(%r30),%r29 
-    LDD     -288(%r30),%r27
-    B       $D0         
-    LDD     -368(%r30),%r2  
-	.PROCEND	;in=24,25,26,29;out=28;
-
-;----------------------------------------------------------------------------
-;
-; Registers to hold 64-bit values to manipulate.  The "L" part
-; of the register corresponds to the upper 32-bits, while the "R"
-; part corresponds to the lower 32-bits
-; 
-; Note, that when using b6 and b7, the code must save these before
-; using them because they are callee save registers 
-; 
-;
-; Floating point registers to use to save values that
-; are manipulated.  These don't collide with ftemp1-6 and
-; are all caller save registers
-;
-a0        .reg %fr22
-a0L       .reg %fr22L
-a0R       .reg %fr22R
-
-a1        .reg %fr23
-a1L       .reg %fr23L
-a1R       .reg %fr23R
-
-a2        .reg %fr24
-a2L       .reg %fr24L
-a2R       .reg %fr24R
-
-a3        .reg %fr25
-a3L       .reg %fr25L
-a3R       .reg %fr25R
-
-a4        .reg %fr26
-a4L       .reg %fr26L
-a4R       .reg %fr26R
-
-a5        .reg %fr27
-a5L       .reg %fr27L
-a5R       .reg %fr27R
-
-a6        .reg %fr28
-a6L       .reg %fr28L
-a6R       .reg %fr28R
-
-a7        .reg %fr29
-a7L       .reg %fr29L
-a7R       .reg %fr29R
-
-b0        .reg %fr30
-b0L       .reg %fr30L
-b0R       .reg %fr30R
-
-b1        .reg %fr31
-b1L       .reg %fr31L
-b1R       .reg %fr31R
-
-;
-; Temporary floating point variables, these are all caller save
-; registers
-;
-ftemp1    .reg %fr4
-ftemp2    .reg %fr5
-ftemp3    .reg %fr6
-ftemp4    .reg %fr7
-
-;
-; The B set of registers when used.
-;
-
-b2        .reg %fr8
-b2L       .reg %fr8L
-b2R       .reg %fr8R
-
-b3        .reg %fr9
-b3L       .reg %fr9L
-b3R       .reg %fr9R
-
-b4        .reg %fr10
-b4L       .reg %fr10L
-b4R       .reg %fr10R
-
-b5        .reg %fr11
-b5L       .reg %fr11L
-b5R       .reg %fr11R
-
-b6        .reg %fr12
-b6L       .reg %fr12L
-b6R       .reg %fr12R
-
-b7        .reg %fr13
-b7L       .reg %fr13L
-b7R       .reg %fr13R
-
-c1           .reg %r21   ; only reg
-temp1        .reg %r20   ; only reg
-temp2        .reg %r19   ; only reg
-temp3        .reg %r31   ; only reg
-
-m1           .reg %r28   
-c2           .reg %r23   
-high_one     .reg %r1
-ht           .reg %r6
-lt           .reg %r5
-m            .reg %r4
-c3           .reg %r3
-
-SQR_ADD_C  .macro  A0L,A0R,C1,C2,C3
-    XMPYU   A0L,A0R,ftemp1       ; m
-    FSTD    ftemp1,-24(%sp)      ; store m
-
-    XMPYU   A0R,A0R,ftemp2       ; lt
-    FSTD    ftemp2,-16(%sp)      ; store lt
-
-    XMPYU   A0L,A0L,ftemp3       ; ht
-    FSTD    ftemp3,-8(%sp)       ; store ht
-
-    LDD     -24(%sp),m           ; load m
-    AND     m,high_mask,temp2    ; m & Mask
-    DEPD,Z  m,30,31,temp3        ; m << 32+1
-    LDD     -16(%sp),lt          ; lt
-
-    LDD     -8(%sp),ht           ; ht
-    EXTRD,U temp2,32,33,temp1    ; temp1 = m&Mask >> 32-1
-    ADD     temp3,lt,lt          ; lt = lt+m
-    ADD,L   ht,temp1,ht          ; ht += temp1
-    ADD,DC  ht,%r0,ht            ; ht++
-
-    ADD     C1,lt,C1             ; c1=c1+lt
-    ADD,DC  ht,%r0,ht            ; ht++
-
-    ADD     C2,ht,C2             ; c2=c2+ht
-    ADD,DC  C3,%r0,C3            ; c3++
-.endm
-
-SQR_ADD_C2 .macro  A0L,A0R,A1L,A1R,C1,C2,C3
-    XMPYU   A0L,A1R,ftemp1          ; m1 = bl*ht
-    FSTD    ftemp1,-16(%sp)         ;
-    XMPYU   A0R,A1L,ftemp2          ; m = bh*lt
-    FSTD    ftemp2,-8(%sp)          ;
-    XMPYU   A0R,A1R,ftemp3          ; lt = bl*lt
-    FSTD    ftemp3,-32(%sp)
-    XMPYU   A0L,A1L,ftemp4          ; ht = bh*ht
-    FSTD    ftemp4,-24(%sp)         ;
-
-    LDD     -8(%sp),m               ; r21 = m
-    LDD     -16(%sp),m1             ; r19 = m1
-    ADD,L   m,m1,m                  ; m+m1
-
-    DEPD,Z  m,31,32,temp3           ; (m+m1<<32)
-    LDD     -24(%sp),ht             ; r24 = ht
-
-    CMPCLR,*>>= m,m1,%r0            ; if (m < m1)
-    ADD,L   ht,high_one,ht          ; ht+=high_one
-
-    EXTRD,U m,31,32,temp1           ; m >> 32
-    LDD     -32(%sp),lt             ; lt
-    ADD,L   ht,temp1,ht             ; ht+= m>>32
-    ADD     lt,temp3,lt             ; lt = lt+m1
-    ADD,DC  ht,%r0,ht               ; ht++
-
-    ADD     ht,ht,ht                ; ht=ht+ht;
-    ADD,DC  C3,%r0,C3               ; add in carry (c3++)
-
-    ADD     lt,lt,lt                ; lt=lt+lt;
-    ADD,DC  ht,%r0,ht               ; add in carry (ht++)
-
-    ADD     C1,lt,C1                ; c1=c1+lt
-    ADD,DC,*NUV ht,%r0,ht           ; add in carry (ht++)
-    LDO     1(C3),C3              ; bump c3 if overflow,nullify otherwise
-
-    ADD     C2,ht,C2                ; c2 = c2 + ht
-    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
-.endm
-
-;
-;void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
-; arg0 = r_ptr
-; arg1 = a_ptr
-;
-
-bn_sqr_comba8
-	.PROC
-	.CALLINFO FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .ENTRY
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD     0(a_ptr),a0       
-    FLDD     8(a_ptr),a1       
-    FLDD    16(a_ptr),a2       
-    FLDD    24(a_ptr),a3       
-    FLDD    32(a_ptr),a4       
-    FLDD    40(a_ptr),a5       
-    FLDD    48(a_ptr),a6       
-    FLDD    56(a_ptr),a7       
-
-	SQR_ADD_C a0L,a0R,c1,c2,c3
-	STD     c1,0(r_ptr)          ; r[0] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
-	STD     c2,8(r_ptr)          ; r[1] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
-	STD     c3,16(r_ptr)            ; r[2] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
-	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
-	STD     c1,24(r_ptr)           ; r[3] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
-	SQR_ADD_C2 a4L,a4R,a0L,a0R,c2,c3,c1
-	STD     c2,32(r_ptr)          ; r[4] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a5L,a5R,a0L,a0R,c3,c1,c2
-	SQR_ADD_C2 a4L,a4R,a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
-	STD     c3,40(r_ptr)          ; r[5] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C a3L,a3R,c1,c2,c3
-	SQR_ADD_C2 a4L,a4R,a2L,a2R,c1,c2,c3
-	SQR_ADD_C2 a5L,a5R,a1L,a1R,c1,c2,c3
-	SQR_ADD_C2 a6L,a6R,a0L,a0R,c1,c2,c3
-	STD     c1,48(r_ptr)          ; r[6] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a7L,a7R,a0L,a0R,c2,c3,c1
-	SQR_ADD_C2 a6L,a6R,a1L,a1R,c2,c3,c1
-	SQR_ADD_C2 a5L,a5R,a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a4L,a4R,a3L,a3R,c2,c3,c1
-	STD     c2,56(r_ptr)          ; r[7] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a4L,a4R,c3,c1,c2
-	SQR_ADD_C2 a5L,a5R,a3L,a3R,c3,c1,c2
-	SQR_ADD_C2 a6L,a6R,a2L,a2R,c3,c1,c2
-	SQR_ADD_C2 a7L,a7R,a1L,a1R,c3,c1,c2
-	STD     c3,64(r_ptr)          ; r[8] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a7L,a7R,a2L,a2R,c1,c2,c3
-	SQR_ADD_C2 a6L,a6R,a3L,a3R,c1,c2,c3
-	SQR_ADD_C2 a5L,a5R,a4L,a4R,c1,c2,c3
-	STD     c1,72(r_ptr)          ; r[9] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a5L,a5R,c2,c3,c1
-	SQR_ADD_C2 a6L,a6R,a4L,a4R,c2,c3,c1
-	SQR_ADD_C2 a7L,a7R,a3L,a3R,c2,c3,c1
-	STD     c2,80(r_ptr)          ; r[10] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a7L,a7R,a4L,a4R,c3,c1,c2
-	SQR_ADD_C2 a6L,a6R,a5L,a5R,c3,c1,c2
-	STD     c3,88(r_ptr)          ; r[11] = c3;
-	COPY    %r0,c3
-	
-	SQR_ADD_C a6L,a6R,c1,c2,c3
-	SQR_ADD_C2 a7L,a7R,a5L,a5R,c1,c2,c3
-	STD     c1,96(r_ptr)          ; r[12] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a7L,a7R,a6L,a6R,c2,c3,c1
-	STD     c2,104(r_ptr)         ; r[13] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a7L,a7R,c3,c1,c2
-	STD     c3, 112(r_ptr)       ; r[14] = c3
-	STD     c1, 120(r_ptr)       ; r[15] = c1
-
-    .EXIT
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-;-----------------------------------------------------------------------------
-;
-;void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
-; arg0 = r_ptr
-; arg1 = a_ptr
-;
-
-bn_sqr_comba4
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_sqr_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD     0(a_ptr),a0       
-    FLDD     8(a_ptr),a1       
-    FLDD    16(a_ptr),a2       
-    FLDD    24(a_ptr),a3       
-    FLDD    32(a_ptr),a4       
-    FLDD    40(a_ptr),a5       
-    FLDD    48(a_ptr),a6       
-    FLDD    56(a_ptr),a7       
-
-	SQR_ADD_C a0L,a0R,c1,c2,c3
-
-	STD     c1,0(r_ptr)          ; r[0] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
-
-	STD     c2,8(r_ptr)          ; r[1] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C a1L,a1R,c3,c1,c2
-	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
-
-	STD     c3,16(r_ptr)            ; r[2] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
-	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
-
-	STD     c1,24(r_ptr)           ; r[3] = c1;
-	COPY    %r0,c1
-
-	SQR_ADD_C a2L,a2R,c2,c3,c1
-	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
-
-	STD     c2,32(r_ptr)           ; r[4] = c2;
-	COPY    %r0,c2
-
-	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
-	STD     c3,40(r_ptr)           ; r[5] = c3;
-	COPY    %r0,c3
-
-	SQR_ADD_C a3L,a3R,c1,c2,c3
-	STD     c1,48(r_ptr)           ; r[6] = c1;
-	STD     c2,56(r_ptr)           ; r[7] = c2;
-
-    .EXIT
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-
-;---------------------------------------------------------------------------
-
-MUL_ADD_C  .macro  A0L,A0R,B0L,B0R,C1,C2,C3
-    XMPYU   A0L,B0R,ftemp1        ; m1 = bl*ht
-    FSTD    ftemp1,-16(%sp)       ;
-    XMPYU   A0R,B0L,ftemp2        ; m = bh*lt
-    FSTD    ftemp2,-8(%sp)        ;
-    XMPYU   A0R,B0R,ftemp3        ; lt = bl*lt
-    FSTD    ftemp3,-32(%sp)
-    XMPYU   A0L,B0L,ftemp4        ; ht = bh*ht
-    FSTD    ftemp4,-24(%sp)       ;
-
-    LDD     -8(%sp),m             ; r21 = m
-    LDD     -16(%sp),m1           ; r19 = m1
-    ADD,L   m,m1,m                ; m+m1
-
-    DEPD,Z  m,31,32,temp3         ; (m+m1<<32)
-    LDD     -24(%sp),ht           ; r24 = ht
-
-    CMPCLR,*>>= m,m1,%r0          ; if (m < m1)
-    ADD,L   ht,high_one,ht        ; ht+=high_one
-
-    EXTRD,U m,31,32,temp1         ; m >> 32
-    LDD     -32(%sp),lt           ; lt
-    ADD,L   ht,temp1,ht           ; ht+= m>>32
-    ADD     lt,temp3,lt           ; lt = lt+m1
-    ADD,DC  ht,%r0,ht             ; ht++
-
-    ADD     C1,lt,C1              ; c1=c1+lt
-    ADD,DC  ht,%r0,ht             ; bump c3 if overflow,nullify otherwise
-
-    ADD     C2,ht,C2              ; c2 = c2 + ht
-    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
-.endm
-
-
-;
-;void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg2 = b_ptr
-;
-
-bn_mul_comba8
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_mul_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-    FSTD    %fr12,32(%sp)       ; save r6
-    FSTD    %fr13,40(%sp)       ; save r7
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD      0(a_ptr),a0       
-    FLDD      8(a_ptr),a1       
-    FLDD     16(a_ptr),a2       
-    FLDD     24(a_ptr),a3       
-    FLDD     32(a_ptr),a4       
-    FLDD     40(a_ptr),a5       
-    FLDD     48(a_ptr),a6       
-    FLDD     56(a_ptr),a7       
-
-    FLDD      0(b_ptr),b0       
-    FLDD      8(b_ptr),b1       
-    FLDD     16(b_ptr),b2       
-    FLDD     24(b_ptr),b3       
-    FLDD     32(b_ptr),b4       
-    FLDD     40(b_ptr),b5       
-    FLDD     48(b_ptr),b6       
-    FLDD     56(b_ptr),b7       
-
-	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
-	STD       c1,0(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
-	STD       c2,8(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
-	STD       c3,16(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
-	STD       c1,24(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a4L,a4R,b0L,b0R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a0L,a0R,b4L,b4R,c2,c3,c1
-	STD       c2,32(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a0L,a0R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b4L,b4R,c3,c1,c2
-	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
-	MUL_ADD_C a4L,a4R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b0L,b0R,c3,c1,c2
-	STD       c3,40(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a6L,a6R,b0L,b0R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a4L,a4R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b4L,b4R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a0L,a0R,b6L,b6R,c1,c2,c3
-	STD       c1,48(r_ptr)
-	COPY      %r0,c1
-	
-	MUL_ADD_C a0L,a0R,b7L,b7R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b6L,b6R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b5L,b5R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b4L,b4R,c2,c3,c1
-	MUL_ADD_C a4L,a4R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a5L,a5R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a6L,a6R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a7L,a7R,b0L,b0R,c2,c3,c1
-	STD       c2,56(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a7L,a7R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a6L,a6R,b2L,b2R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a4L,a4R,b4L,b4R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a2L,a2R,b6L,b6R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b7L,b7R,c3,c1,c2
-	STD       c3,64(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a2L,a2R,b7L,b7R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b6L,b6R,c1,c2,c3
-	MUL_ADD_C a4L,a4R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b4L,b4R,c1,c2,c3
-	MUL_ADD_C a6L,a6R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a7L,a7R,b2L,b2R,c1,c2,c3
-	STD       c1,72(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a7L,a7R,b3L,b3R,c2,c3,c1
-	MUL_ADD_C a6L,a6R,b4L,b4R,c2,c3,c1
-	MUL_ADD_C a5L,a5R,b5L,b5R,c2,c3,c1
-	MUL_ADD_C a4L,a4R,b6L,b6R,c2,c3,c1
-	MUL_ADD_C a3L,a3R,b7L,b7R,c2,c3,c1
-	STD       c2,80(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a4L,a4R,b7L,b7R,c3,c1,c2
-	MUL_ADD_C a5L,a5R,b6L,b6R,c3,c1,c2
-	MUL_ADD_C a6L,a6R,b5L,b5R,c3,c1,c2
-	MUL_ADD_C a7L,a7R,b4L,b4R,c3,c1,c2
-	STD       c3,88(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a7L,a7R,b5L,b5R,c1,c2,c3
-	MUL_ADD_C a6L,a6R,b6L,b6R,c1,c2,c3
-	MUL_ADD_C a5L,a5R,b7L,b7R,c1,c2,c3
-	STD       c1,96(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a6L,a6R,b7L,b7R,c2,c3,c1
-	MUL_ADD_C a7L,a7R,b6L,b6R,c2,c3,c1
-	STD       c2,104(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a7L,a7R,b7L,b7R,c3,c1,c2
-	STD       c3,112(r_ptr)
-	STD       c1,120(r_ptr)
-
-    .EXIT
-    FLDD    -88(%sp),%fr13 
-    FLDD    -96(%sp),%fr12 
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-;-----------------------------------------------------------------------------
-;
-;void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
-; arg0 = r_ptr
-; arg1 = a_ptr
-; arg2 = b_ptr
-;
-
-bn_mul_comba4
-	.proc
-	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
-	.EXPORT	bn_mul_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
-    .entry
-	.align 64
-
-    STD     %r3,0(%sp)          ; save r3
-    STD     %r4,8(%sp)          ; save r4
-    STD     %r5,16(%sp)         ; save r5
-    STD     %r6,24(%sp)         ; save r6
-    FSTD    %fr12,32(%sp)       ; save r6
-    FSTD    %fr13,40(%sp)       ; save r7
-
-	;
-	; Zero out carries
-	;
-	COPY     %r0,c1
-	COPY     %r0,c2
-	COPY     %r0,c3
-
-	LDO      128(%sp),%sp       ; bump stack
-    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
-
-	;
-	; Load up all of the values we are going to use
-	;
-    FLDD      0(a_ptr),a0       
-    FLDD      8(a_ptr),a1       
-    FLDD     16(a_ptr),a2       
-    FLDD     24(a_ptr),a3       
-
-    FLDD      0(b_ptr),b0       
-    FLDD      8(b_ptr),b1       
-    FLDD     16(b_ptr),b2       
-    FLDD     24(b_ptr),b3       
-
-	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
-	STD       c1,0(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
-	STD       c2,8(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
-	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
-	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
-	STD       c3,16(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
-	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
-	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
-	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
-	STD       c1,24(r_ptr)
-	COPY      %r0,c1
-
-	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
-	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
-	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
-	STD       c2,32(r_ptr)
-	COPY      %r0,c2
-
-	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
-	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
-	STD       c3,40(r_ptr)
-	COPY      %r0,c3
-
-	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
-	STD       c1,48(r_ptr)
-	STD       c2,56(r_ptr)
-
-    .EXIT
-    FLDD    -88(%sp),%fr13 
-    FLDD    -96(%sp),%fr12 
-    LDD     -104(%sp),%r6        ; restore r6
-    LDD     -112(%sp),%r5        ; restore r5
-    LDD     -120(%sp),%r4        ; restore r4
-    BVE     (%rp)
-    LDD,MB  -128(%sp),%r3
-
-	.PROCEND	
-
-
-	.SPACE	$TEXT$
-	.SUBSPA	$CODE$
-	.SPACE	$PRIVATE$,SORT=16
-	.IMPORT	$global$,DATA
-	.SPACE	$TEXT$
-	.SUBSPA	$CODE$
-	.SUBSPA	$LIT$,ACCESS=0x2c
-C$4
-	.ALIGN	8
-	.STRINGZ	"Division would overflow (%d)\n"
-	.END
diff --git a/src/third_party/skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/third_party/skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index d5d3348..56c2fe1 100755
--- a/src/third_party/skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/third_party/skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -86,7 +86,8 @@
         fsBuilder->codeAppend("\tfloat afwidth;\n");
         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
             // this gives us a smooth step across approximately one fragment
-            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n");
+            // we use y to work around a Mali400 bug in the x direction
+            fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));\n");
         } else {
             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
@@ -305,8 +306,8 @@
         fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
         bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
         if (isUniformScale) {
-            fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
-            fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
+            fsBuilder->codeAppend("\tfloat dy = abs(dFdy(st.y));\n");
+            fsBuilder->codeAppendf("\tvec2 offset = vec2(dy*%s.z, 0.0);\n", textureSizeUniName);
         } else {
             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
@@ -347,7 +348,7 @@
         fsBuilder->codeAppend("\tfloat afwidth;\n");
         if (isUniformScale) {
             // this gives us a smooth step across approximately one fragment
-            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n");
+            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dy;\n");
         } else {
             fsBuilder->codeAppend("\tvec2 uv_grad;\n");
             if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
diff --git a/src/third_party/skia/src/gpu/gl/GrGLCaps.cpp b/src/third_party/skia/src/gpu/gl/GrGLCaps.cpp
index e6ea4a7..ab22e62 100644
--- a/src/third_party/skia/src/gpu/gl/GrGLCaps.cpp
+++ b/src/third_party/skia/src/gpu/gl/GrGLCaps.cpp
@@ -197,6 +197,28 @@
         }
     }
 
+    if (fTextureRedSupport) {
+        // Some devices claim to support GL_RED, but actually do not, so we
+        // verify support by actually attempting to create a GL_RED texture.
+        // As an example, one device was found to claim GLES 3.0 support, but
+        // could not create GL_RED textures.
+        GrGLenum error;
+        GrGLuint texture_id;
+        GR_GL_CALL(gli, GenTextures(1, &texture_id));
+        GR_GL_CALL(gli, BindTexture(GR_GL_TEXTURE_2D, texture_id));
+        GR_GL_CALL_NOERRCHECK(gli, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RED,
+                                              64, 64, 0, GR_GL_RED,
+                                              GR_GL_UNSIGNED_BYTE, 0));
+        GR_GL_CALL_RET(gli, error, GetError());
+        if (error != GR_GL_NO_ERROR) {
+            // There was an error creating the texture, do not advertise GL_RED
+            // support.
+            fTextureRedSupport = false;
+        }
+        GR_GL_CALL(gli, BindTexture(GR_GL_TEXTURE_2D, 0));
+        GR_GL_CALL(gli, DeleteTextures(1, &texture_id));
+    }
+
     fImagingSupport = kGL_GrGLStandard == standard &&
                       ctxInfo.hasExtension("GL_ARB_imaging");
 
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index d8fe41e..6294478 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -76,7 +76,7 @@
 is_linux = platform.system() == 'Linux'
 is_windows = platform.system() == 'Windows'
 
-microsoft_flavors = ['win', 'win-console', 'xb1', 'xb1-future']
+microsoft_flavors = ['win', 'win-console', 'win-lib', 'xb1', 'xb1-future']
 sony_flavors = ['ps3', 'ps4']
 windows_host_flavors = microsoft_flavors + sony_flavors
 
diff --git a/src/tools/gyp/pylib/gyp/msvs_emulation.py b/src/tools/gyp/pylib/gyp/msvs_emulation.py
index ba20472..1e58bf6 100755
--- a/src/tools/gyp/pylib/gyp/msvs_emulation.py
+++ b/src/tools/gyp/pylib/gyp/msvs_emulation.py
@@ -484,11 +484,6 @@
     ld('Profile', map={ 'true': '/PROFILE'})
     # TODO(scottmg): This should sort of be somewhere else (not really a flag).
     ld('AdditionalDependencies', prefix='')
-    # TODO(scottmg): These too.
-    if not config.startswith('XB1') and not config.startswith('XB360'):
-      ldflags.extend(('kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib',
-          'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib',
-          'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'DelayImp.lib'))
 
     if not config.startswith('XB360'):
       # If the base address is not specifically controlled, DYNAMICBASE should
@@ -517,19 +512,12 @@
   def _GetLdManifestFlags(self, config, name, allow_isolation):
     """Returns the set of flags that need to be added to the link to generate
     a default manifest, as well as the name of the generated file."""
-    # Add manifest flags that mirror the defaults in VS. Chromium dev builds
-    # do not currently use any non-default settings, but we could parse
-    # VCManifestTool blocks if Chromium or other projects need them in the
-    # future. Of particular note, we do not yet support EmbedManifest because
-    # it complicates incremental linking.
     output_name = name + '.intermediate.manifest'
+    # Manifests are off for UWP. If needed by another target,
+    # please find a way to configure them per target.
     flags = [
-      '/MANIFEST',
-      '/ManifestFile:' + output_name,
-      '''/MANIFESTUAC:"level='asInvoker' uiAccess='false'"'''
+      '/MANIFEST:NO',
     ]
-    if allow_isolation:
-      flags.append('/ALLOWISOLATION')
     return flags, output_name
 
   def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):