Commit 7d406320 authored by Karl Tomlinson's avatar Karl Tomlinson
Browse files

Bug 1473463 evaluate worklet scripts as modules without support for nested import r=baku

The separation of parse and evaluate steps permits implementation of behavior
on unhandled exception during evaluation that is different from that on
parsing error.

Implementation of fetching a complete module script graph is tracked in
https://bugzilla.mozilla.org/show_bug.cgi?id=1572644

Differential Revision: https://phabricator.services.mozilla.com/D41339

--HG--
extra : moz-landing-system : lando
parent 859de114
Loading
Loading
Loading
Loading
+40 −12
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/WorkletImpl.h"
#include "js/CompilationAndEvaluation.h"
#include "js/Modules.h"
#include "js/SourceText.h"
#include "nsIInputStreamPump.h"
#include "nsIThreadRetargetableRequest.h"
@@ -50,6 +50,8 @@ class ExecutionRunnable final : public Runnable {

  void RunOnMainThread();

  bool ParseAndLinkModule(JSContext* aCx, JS::MutableHandle<JSObject*> aModule);

  RefPtr<WorkletFetchHandler> mHandler;
  RefPtr<WorkletImpl> mWorkletImpl;
  JS::UniqueTwoByteChars mScriptBuffer;
@@ -336,6 +338,33 @@ ExecutionRunnable::Run() {
  return NS_OK;
}

bool ExecutionRunnable::ParseAndLinkModule(
    JSContext* aCx, JS::MutableHandle<JSObject*> aModule) {
  JS::CompileOptions compileOptions(aCx);
  compileOptions.setIntroductionType("Worklet");
  compileOptions.setFileAndLine(mHandler->URL().get(), 0);
  compileOptions.setIsRunOnce(true);
  compileOptions.setNoScriptRval(true);

  JS::SourceText<char16_t> buffer;
  if (!buffer.init(aCx, std::move(mScriptBuffer), mScriptLength)) {
    return false;
  }
  JS::Rooted<JSObject*> module(aCx,
                               JS::CompileModule(aCx, compileOptions, buffer));
  if (!module) {
    return false;
  }
  // Link() was previously named Instantiate().
  // https://github.com/tc39/ecma262/pull/1312
  // Any imports will fail here - bug 1572644.
  if (!JS::ModuleInstantiate(aCx, module)) {
    return false;
  }
  aModule.set(module);
  return true;
}

void ExecutionRunnable::RunOnWorkletThread() {
  WorkletThread::EnsureCycleCollectedJSContext(mParentRuntime);

@@ -346,19 +375,10 @@ void ExecutionRunnable::RunOnWorkletThread() {
  JSContext* cx = aes.cx();

  JS::Rooted<JSObject*> globalObj(cx, globalScope->GetGlobalJSObject());

  JS::CompileOptions compileOptions(cx);
  compileOptions.setIntroductionType("Worklet");
  compileOptions.setFileAndLine(mHandler->URL().get(), 0);
  compileOptions.setIsRunOnce(true);
  compileOptions.setNoScriptRval(true);

  JSAutoRealm ar(cx, globalObj);

  JS::Rooted<JS::Value> unused(cx);
  JS::SourceText<char16_t> buffer;
  if (!buffer.init(cx, std::move(mScriptBuffer), mScriptLength) ||
      !JS::Evaluate(cx, compileOptions, buffer, &unused)) {
  JS::Rooted<JSObject*> module(cx);
  if (!ParseAndLinkModule(cx, &module)) {
    ErrorResult error;
    error.MightThrowJSException();
    error.StealExceptionFromJSContext(cx);
@@ -366,6 +386,14 @@ void ExecutionRunnable::RunOnWorkletThread() {
    return;
  }

  // https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
  // invokes
  // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script
  // without /rethrow errors/ and so unhandled exceptions do not cause the
  // promise to be rejected.
  JS::ModuleEvaluate(cx, module);
  JS::Rooted<JS::Value> unused(cx);

  // All done.
  mResult = NS_OK;
}
+2 −2
Original line number Diff line number Diff line
@@ -32,9 +32,9 @@ function runTestInIframe() {
    return audioContext.audioWorklet.addModule("worklet_exception.js")
  })
  .then(() => {
    ok(false, "We should not be called!");
    ok(true, "The script threw but we are still here.");
  }, () => {
    ok(true, "The script thrown but we are still here.");
    ok(false, "We should not be called!");
  })

  .then(() => {
+6 −1
Original line number Diff line number Diff line
[audioworkletglobalscope-sample-rate.https.html]
  bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1572627
  expected:
    if release_or_beta: OK
    ERROR
  [\n      Test sampleRate in AudioWorkletGlobalScope\n    ]
    expected: FAIL
    expected:
      if release_or_beta: FAIL
+2 −1
Original line number Diff line number Diff line
@@ -18,7 +18,8 @@
    expected: FAIL

  [Importing a script which throws should still resolve the given promise.]
    expected: FAIL
    expected:
      if release_or_beta: FAIL

  [Importing a non-existent script rejects the given promise with an AbortError.]
    expected: FAIL