Revert "[blink] Remove old script streamer thread"

This reverts commit 96c748b0b0e61d207ef1d3bd70238b3443179b77.

Reason for revert: it's suspect in failures 
https://ci.chromium.org/p/chromium/builders/ci/Win7%20Tests%20%281%29/88931

Original change's description:
> [blink] Remove old script streamer thread
> 
> The script streamer thread has now been replaced with posting tasks to
> the scheduler, so remove the flag picking between the two options and
> the dedicated streaming thread itself.
> 
> Also, remove the streaming task re-posting now that the blocking/
> non-blocking worker pools are merged.
> 
> Bug: 874080
> Change-Id: Ib9dabb91deddcc616d4edfe5efb13d8e584c0691
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1503420
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Reviewed-by: Steven Holte <holte@chromium.org>
> Reviewed-by: Kentaro Hara <haraken@chromium.org>
> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
> Commit-Queue: Kinuko Yasuda <kinuko@chromium.org>
> Auto-Submit: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#638031}

TBR=kinuko@chromium.org,haraken@chromium.org,holte@chromium.org,mlippautz@chromium.org,leszeks@chromium.org

Change-Id: Ia67f3fcfbff3155f9da4b53f371115f3dfd0089c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 874080
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1505412
Reviewed-by: Vadym Doroshenko <dvadym@chromium.org>
Commit-Queue: Vadym Doroshenko <dvadym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638055}
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 98977d2a..6f69859 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -368,6 +368,9 @@
   WebRuntimeFeatures::EnableModernMediaControls(
       base::FeatureList::IsEnabled(media::kUseModernMediaControls));
 
+  WebRuntimeFeatures::EnableScheduledScriptStreaming(
+      base::FeatureList::IsEnabled(features::kScheduledScriptStreaming));
+
   WebRuntimeFeatures::EnableScriptStreamingOnPreload(
       base::FeatureList::IsEnabled(features::kScriptStreamingOnPreload));
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 76452b9a..77c3453 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -658,6 +658,10 @@
 const base::Feature kWipeCorruptV2IDBDatabases{
     "WipeCorruptV2IDBDatabases", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enabled scheduler use for script streaming.
+const base::Feature kScheduledScriptStreaming{"ScheduledScriptStreaming",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Start streaming scripts on script preload.
 const base::Feature kScriptStreamingOnPreload{
     "ScriptStreamingOnPreload", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 6876635..b0519d3 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -145,6 +145,7 @@
 CONTENT_EXPORT extern const base::Feature kWebXrGamepadSupport;
 CONTENT_EXPORT extern const base::Feature kWebXrHitTest;
 CONTENT_EXPORT extern const base::Feature kWipeCorruptV2IDBDatabases;
+CONTENT_EXPORT extern const base::Feature kScheduledScriptStreaming;
 CONTENT_EXPORT extern const base::Feature kScriptStreamingOnPreload;
 
 #if defined(OS_ANDROID)
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index d6a573e..8f5c140f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4349,6 +4349,25 @@
             ]
         }
     ],
+    "ScheduledScriptStreaming": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "ScheduledScriptStreaming",
+                    "enable_features": [
+                        "ScheduledScriptStreaming"
+                    ]
+                }
+            ]
+        }
+    ],
     "SearchEnginePromo": [
         {
             "platforms": [
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index d51c3c5..43b85f53 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -219,6 +219,7 @@
   BLINK_PLATFORM_EXPORT static void EnableMediaEngagementBypassAutoplayPolicies(
       bool);
   BLINK_PLATFORM_EXPORT static void EnableAutomationControlled(bool);
+  BLINK_PLATFORM_EXPORT static void EnableScheduledScriptStreaming(bool);
   BLINK_PLATFORM_EXPORT static void EnableScriptStreamingOnPreload(bool);
   BLINK_PLATFORM_EXPORT static void EnableExperimentalProductivityFeatures(
       bool);
diff --git a/third_party/blink/public/platform/web_thread_type.h b/third_party/blink/public/platform/web_thread_type.h
index 38ace6b..7f0cf64 100644
--- a/third_party/blink/public/platform/web_thread_type.h
+++ b/third_party/blink/public/platform/web_thread_type.h
@@ -21,7 +21,7 @@
   kFileThread = 8,
   kDatabaseThread = 9,
   kWebAudioThread = 10,
-  // 11 was kScriptStreamerThread, which was deleted
+  kScriptStreamerThread = 11,
   kOfflineAudioRenderThread = 12,
   kReverbConvolutionBackgroundThread = 13,
   kHRTFDatabaseLoaderThread = 14,
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index ee2e9a5..7dff426 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -100,6 +100,8 @@
                     "core/v8/script_source_location_type.h",
                     "core/v8/script_streamer.cc",
                     "core/v8/script_streamer.h",
+                    "core/v8/script_streamer_thread.cc",
+                    "core/v8/script_streamer_thread.h",
                     "core/v8/script_value.cc",
                     "core/v8/script_value.h",
                     "core/v8/serialization/post_message_helper.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
index 6836cf1..e58b16d 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
@@ -8,6 +8,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -351,6 +352,21 @@
   streamer->StreamingCompleteOnBackgroundThread();
 }
 
+void RunBlockingScriptStreamingTask(
+    std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task,
+    ScriptStreamer* streamer,
+    std::atomic_flag* blocking_task_started_or_cancelled) {
+  if (blocking_task_started_or_cancelled->test_and_set())
+    return;
+  RunScriptStreamingTask(std::move(task), streamer);
+}
+
+void RunNonBlockingScriptStreamingTask(
+    std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task,
+    ScriptStreamer* streamer) {
+  RunScriptStreamingTask(std::move(task), streamer);
+}
+
 }  // namespace
 
 bool ScriptStreamer::HasEnoughDataForStreaming(size_t resource_buffer_size) {
@@ -399,6 +415,16 @@
       }
     }
 
+    if (!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled() &&
+        ScriptStreamerThread::Shared()->IsRunningTask()) {
+      // If scheduled script streaming is disabled, we only have one thread for
+      // running the tasks. A new task shouldn't be queued before the running
+      // task completes, because the running task can block and wait for data
+      // from the network.
+      SuppressStreaming(kThreadBusy);
+      return;
+    }
+
     DCHECK(!stream_);
     DCHECK(!source_);
     stream_ = new SourceStream;
@@ -425,16 +451,31 @@
         inspector_parse_script_event::Data(this->ScriptResourceIdentifier(),
                                            this->ScriptURLString()));
 
-    // Script streaming tasks are high priority, as they can block the parser,
-    // and they can (and probably will) block during their own execution as
-    // they wait for more input.
-    //
-    // TODO(leszeks): Decrease the priority of these tasks where possible.
-    worker_pool::PostTaskWithTraits(
-        FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
-        CrossThreadBind(RunScriptStreamingTask,
-                        WTF::Passed(std::move(script_streaming_task)),
-                        WrapCrossThreadPersistent(this)));
+    if (RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled()) {
+      // Script streaming tasks are high priority, as they can block the parser,
+      // and they can (and probably will) block during their own execution as
+      // they wait for more input.
+      //
+      // Pass through the atomic cancellation token which is set to true by the
+      // task when it is started, or set to true by the streamer if it wants to
+      // cancel the task.
+      //
+      // TODO(leszeks): Decrease the priority of these tasks where possible.
+      worker_pool::PostTaskWithTraits(
+          FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
+          CrossThreadBind(RunBlockingScriptStreamingTask,
+                          WTF::Passed(std::move(script_streaming_task)),
+                          WrapCrossThreadPersistent(this),
+                          WTF::CrossThreadUnretained(
+                              &blocking_task_started_or_cancelled_)));
+    } else {
+      blocking_task_started_or_cancelled_.test_and_set();
+      ScriptStreamerThread::Shared()->PostTask(
+          CrossThreadBind(&ScriptStreamerThread::RunScriptStreamingTask,
+                          WTF::Passed(std::move(script_streaming_task)),
+                          WrapCrossThreadPersistent(this)));
+    }
+
   }
   if (stream_)
     stream_->DidReceiveData(script_resource_, this);
@@ -451,7 +492,34 @@
   }
 
   if (stream_) {
+    // Mark the stream as finished loading before potentially re-posting the
+    // task to avoid a race between this finish and the task's first read.
     stream_->DidFinishLoading();
+
+    // If the corresponding blocking task hasn't started yet, cancel it and post
+    // a non-blocking task, since we know now that all the data is received and
+    // we will no longer block.
+    //
+    // TODO(874080): Remove this once blocking and non-blocking pools are
+    // merged.
+    if (RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled() &&
+        !RuntimeEnabledFeatures::MergeBlockingNonBlockingPoolsEnabled() &&
+        !blocking_task_started_or_cancelled_.test_and_set()) {
+      std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask>
+          script_streaming_task(
+              base::WrapUnique(v8::ScriptCompiler::StartStreamingScript(
+                  V8PerIsolateData::MainThreadIsolate(), source_.get(),
+                  compile_options_)));
+
+      // The task creation shouldn't fail, since it didn't fail before during
+      // NotifyAppendData.
+      CHECK(script_streaming_task);
+      worker_pool::PostTaskWithTraits(
+          FROM_HERE, {base::TaskPriority::USER_BLOCKING},
+          CrossThreadBind(RunNonBlockingScriptStreamingTask,
+                          WTF::Passed(std::move(script_streaming_task)),
+                          WrapCrossThreadPersistent(this)));
+    }
   }
   loading_finished_ = true;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.h b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
index a162366..32f97c0 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_H_
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_H_
 
+#include <atomic>
 #include <memory>
 
 #include "base/macros.h"
@@ -40,7 +41,8 @@
     kRevalidate,
     kContextNotValid,  // DEPRECATED
     kEncodingNotSupported,
-    kThreadBusy,  // DEPRECATED
+    // TODO(leszeks): Deprecate once scheduled streaming is on by default
+    kThreadBusy,
     kV8CannotStream,
     kScriptTooSmall,
     kNoResourceBuffer,
@@ -153,6 +155,11 @@
   // Whether we have received enough data to start the streaming.
   bool have_enough_data_for_streaming_;
 
+  // Flag used to allow atomic cancelling and reposting of the streaming task
+  // when the load completes without the task yet starting.
+  // TODO(874080): Remove this once blocking and non-blocking pools are merged.
+  std::atomic_flag blocking_task_started_or_cancelled_ = ATOMIC_FLAG_INIT;
+
   // Whether the script source code should be retrieved from the Resource
   // instead of the ScriptStreamer.
   bool streaming_suppressed_;
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
index 4b9ec64..8fd2036 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
@@ -122,6 +123,13 @@
   }
 
   void ProcessTasksUntilStreamingComplete() {
+    if (!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled()) {
+      while (ScriptStreamerThread::Shared()->IsRunningTask()) {
+        test::RunPendingTasks();
+      }
+    }
+    // Once more, because the "streaming complete" notification might only
+    // now be in the task queue.
     test::RunPendingTasks();
   }
 
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.cc
new file mode 100644
index 0000000..e1b3c34
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h"
+
+#include <memory>
+#include "base/location.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+
+namespace blink {
+
+static ScriptStreamerThread* g_shared_thread = nullptr;
+// Guards s_sharedThread. s_sharedThread is initialized and deleted in the main
+// thread, but also used by the streamer thread. Races can occur during
+// shutdown.
+static Mutex* g_mutex = nullptr;
+
+void ScriptStreamerThread::Init() {
+  // Only enabled when ScheduledScriptStreaming is disabled.
+  if (!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled()) {
+    DCHECK(!g_shared_thread);
+    DCHECK(IsMainThread());
+    // This is called in the main thread before any tasks are created, so no
+    // locking is needed.
+    g_mutex = new Mutex();
+    g_shared_thread = new ScriptStreamerThread();
+  }
+}
+
+ScriptStreamerThread* ScriptStreamerThread::Shared() {
+  DCHECK(!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled());
+  return g_shared_thread;
+}
+
+void ScriptStreamerThread::PostTask(CrossThreadClosure task) {
+  DCHECK(!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled());
+  DCHECK(IsMainThread());
+  MutexLocker locker(mutex_);
+  DCHECK(!running_task_);
+  running_task_ = true;
+  PostCrossThreadTask(*PlatformThread().GetTaskRunner(), FROM_HERE,
+                      std::move(task));
+}
+
+void ScriptStreamerThread::TaskDone() {
+  MutexLocker locker(mutex_);
+  DCHECK(running_task_);
+  running_task_ = false;
+}
+
+Thread& ScriptStreamerThread::PlatformThread() {
+  if (!IsRunning()) {
+    thread_ = Platform::Current()->CreateThread(
+        ThreadCreationParams(WebThreadType::kScriptStreamerThread));
+  }
+  return *thread_;
+}
+
+void ScriptStreamerThread::RunScriptStreamingTask(
+    std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task,
+    ScriptStreamer* streamer) {
+  DCHECK(!RuntimeEnabledFeatures::ScheduledScriptStreamingEnabled());
+  TRACE_EVENT1(
+      "v8,devtools.timeline", "v8.parseOnBackground", "data",
+      inspector_parse_script_event::Data(streamer->ScriptResourceIdentifier(),
+                                         streamer->ScriptURLString()));
+  TRACE_EVENT_WITH_FLOW1(
+      TRACE_DISABLED_BY_DEFAULT("v8.compile"), "v8.streamingCompile.run",
+      streamer, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "data",
+      inspector_parse_script_event::Data(streamer->ScriptResourceIdentifier(),
+                                         streamer->ScriptURLString()));
+  // Running the task can and will block: SourceStream::GetSomeData will get
+  // called and it will block and wait for data from the network.
+  task->Run();
+  streamer->StreamingCompleteOnBackgroundThread();
+  MutexLocker locker(*g_mutex);
+  ScriptStreamerThread* thread = Shared();
+  if (thread)
+    thread->TaskDone();
+  // If thread is 0, we're shutting down.
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h b/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h
new file mode 100644
index 0000000..664df34e
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_THREAD_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_THREAD_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ScriptStreamer;
+
+// A singleton thread for running background tasks for script streaming.
+class CORE_EXPORT ScriptStreamerThread {
+  USING_FAST_MALLOC(ScriptStreamerThread);
+
+ public:
+  static void Init();
+  static ScriptStreamerThread* Shared();
+
+  void PostTask(CrossThreadClosure);
+
+  bool IsRunningTask() const {
+    MutexLocker locker(mutex_);
+    return running_task_;
+  }
+
+  void TaskDone();
+
+  static void RunScriptStreamingTask(
+      std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask>,
+      ScriptStreamer*);
+
+ private:
+  ScriptStreamerThread() : running_task_(false) {}
+
+  bool IsRunning() const { return !!thread_; }
+
+  Thread& PlatformThread();
+
+  // At the moment, we only use one thread, so we can only stream one script
+  // at a time. FIXME: Use a thread pool and stream multiple scripts.
+  std::unique_ptr<Thread> thread_;
+  bool running_task_ GUARDED_BY(mutex_);
+  mutable Mutex mutex_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptStreamerThread);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_THREAD_H_
diff --git a/third_party/blink/renderer/core/core_initializer.cc b/third_party/blink/renderer/core/core_initializer.cc
index 45a820c..4b2cc24 100644
--- a/third_party/blink/renderer/core/core_initializer.cc
+++ b/third_party/blink/renderer/core/core_initializer.cc
@@ -32,6 +32,7 @@
 
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/binding_security.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer_thread.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/core/css/media_feature_names.h"
 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
@@ -146,6 +147,7 @@
   V8ThrowDOMException::Init();
 
   BindingSecurity::Init();
+  ScriptStreamerThread::Init();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 5818469..ef919b5 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -594,6 +594,10 @@
   RuntimeEnabledFeatures::SetAutomationControlledEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableScheduledScriptStreaming(bool enable) {
+  RuntimeEnabledFeatures::SetScheduledScriptStreamingEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableScriptStreamingOnPreload(bool enable) {
   RuntimeEnabledFeatures::SetScriptStreamingOnPreloadEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 39b748f..092a107 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1219,6 +1219,9 @@
     {
       name: "RTCUnifiedPlanByDefault",
     },
+    {
+      name: "ScheduledScriptStreaming",
+    },
     // WebSpeech API with both speech recognition and synthesis functionality
     // is not fully enabled on all platforms.
     {
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
index 1576919..2d57044 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
@@ -35,6 +35,7 @@
     case WebThreadType::kHRTFDatabaseLoaderThread:
     case WebThreadType::kOfflineAudioRenderThread:
     case WebThreadType::kReverbConvolutionBackgroundThread:
+    case WebThreadType::kScriptStreamerThread:
     case WebThreadType::kSharedWorkerThread:
     case WebThreadType::kUnspecifiedWorkerThread:
     case WebThreadType::kWebAudioThread:
diff --git a/third_party/blink/renderer/platform/web_thread_type.cc b/third_party/blink/renderer/platform/web_thread_type.cc
index 2c17a78..fd20b80 100644
--- a/third_party/blink/renderer/platform/web_thread_type.cc
+++ b/third_party/blink/renderer/platform/web_thread_type.cc
@@ -33,6 +33,8 @@
       return "Database thread";
     case WebThreadType::kWebAudioThread:
       return "WebAudio thread";
+    case WebThreadType::kScriptStreamerThread:
+      return "ScriptStreamer thread";
     case WebThreadType::kOfflineAudioRenderThread:
       return "OfflineAudioRender thread";
     case WebThreadType::kReverbConvolutionBackgroundThread:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4c5e61c..7a229b4 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -46136,7 +46136,7 @@
   <int value="8" label="FileThread"/>
   <int value="9" label="DatabaseThread"/>
   <int value="10" label="WebAudioThread"/>
-  <int value="11" label="ScriptStreamerThread (obsolete)"/>
+  <int value="11" label="ScriptStreamerThread"/>
   <int value="12" label="OfflineAudioRenderThread"/>
   <int value="13" label="ReverbConvolutionBackgroundThread"/>
   <int value="14" label="HRTFDatabaseLoaderThread"/>