text: // Copyright 2016 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  (function(global, utils, extrasUtils) {
  
  "use strict";
  
  %CheckIsBootstrapping();
  
  // -------------------------------------------------------------------
  // Imports
  
  var AsyncFunctionNext;
  var AsyncFunctionThrow;
  var CreateInternalPromiseCapability;
  var PromiseCreate;
  var PromiseNextMicrotaskID;
  var RejectPromise;
  
  utils.Import(function(from) {
    AsyncFunctionNext = from.AsyncFunctionNext;
    AsyncFunctionThrow = from.AsyncFunctionThrow;
    CreateInternalPromiseCapability = from.CreateInternalPromiseCapability;
    PromiseCreate = from.PromiseCreate;
    RejectPromise = from.RejectPromise;
  });
  
  var promiseAsyncStackIDSymbol =
      utils.ImportNow("promise_async_stack_id_symbol");
  var promiseHandledBySymbol =
      utils.ImportNow("promise_handled_by_symbol");
  var promiseForwardingHandlerSymbol =
      utils.ImportNow("promise_forwarding_handler_symbol");
  var promiseHandledHintSymbol =
      utils.ImportNow("promise_handled_hint_symbol");
  
  // -------------------------------------------------------------------
  
  function PromiseCastResolved(value) {
    // TODO(caitp): This is non spec compliant. See v8:5694.
    if (%is_promise(value)) {
      return value;
    } else {
      var promise = PromiseCreate();
      %promise_resolve(promise, value);
      return promise;
    }
  }
  
  // ES#abstract-ops-async-function-await
  // AsyncFunctionAwait ( value )
  // Shared logic for the core of await. The parser desugars
  //   await awaited
  // into
  //   yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise)
  // The 'awaited' parameter is the value; the generator stands in
  // for the asyncContext, and .promise is the larger promise under
  // construction by the enclosing async function.
  function AsyncFunctionAwait(generator, awaited, outerPromise) {
    // Promise.resolve(awaited).then(
    //     value => AsyncFunctionNext(value),
    //     error => AsyncFunctionThrow(error)
    // );
    var promise = PromiseCastResolved(awaited);
  
    var onFulfilled = sentValue => {
      %_Call(AsyncFunctionNext, generator, sentValue);
      // The resulting Promise is a throwaway, so it doesn't matter what it
      // resolves to. What is important is that we don't end up keeping the
      // whole chain of intermediate Promises alive by returning the value
      // of AsyncFunctionNext, as that would create a memory leak.
      return;
    };
    var onRejected = sentError => {
      %_Call(AsyncFunctionThrow, generator, sentError);
      // Similarly, returning the huge Promise here would cause a long
      // resolution chain to find what the exception to throw is, and
      // create a similar memory leak, and it does not matter what
      // sort of rejection this intermediate Promise becomes.
      return;
    }
  
    // Just forwarding the exception, so no debugEvent for throwawayCapability.
    var throwawayCapability = CreateInternalPromiseCapability(promise);
  
    // The Promise will be thrown away and not handled, but it shouldn't trigger
    // unhandled reject events as its work is done
    %PromiseMarkAsHandled(throwawayCapability.promise);
  
    if (DEBUG_IS_ACTIVE) {
      if (%is_promise(awaited)) {
        // Mark the reject handler callback to be a forwarding edge, rather
        // than a meaningful catch handler
        SET_PRIVATE(onRejected, promiseForwardingHandlerSymbol, true);
      }
  
      // Mark the dependency to outerPromise in case the throwaway Promise is
      // found on the Promise stack
      SET_PRIVATE(throwawayCapability.promise, promiseHandledBySymbol,
                  outerPromise);
    }
  
    %perform_promise_then(promise, onFulfilled, onRejected, throwawayCapability);
  }
  
  // Called by the parser from the desugaring of 'await' when catch
  // prediction indicates no locally surrounding catch block
  function AsyncFunctionAwaitUncaught(generator, awaited, outerPromise) {
    AsyncFunctionAwait(generator, awaited, outerPromise);
  }
  
  // Called by the parser from the desugaring of 'await' when catch
  // prediction indicates that there is a locally surrounding catch block
  function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) {
    if (DEBUG_IS_ACTIVE && %is_promise(awaited)) {
      SET_PRIVATE(awaited, promiseHandledHintSymbol, true);
    }
    AsyncFunctionAwait(generator, awaited, outerPromise);
  }
  
  // How the parser rejects promises from async/await desugaring
  function RejectPromiseNoDebugEvent(promise, reason) {
    return RejectPromise(promise, reason, false);
  }
  
  function AsyncFunctionPromiseCreate() {
    var promise = PromiseCreate();
    if (DEBUG_IS_ACTIVE) {
      // Push the Promise under construction in an async function on
      // the catch prediction stack to handle exceptions thrown before
      // the first await.
      %DebugPushPromise(promise);
      // Assign ID and create a recurring task to save stack for future
      // resumptions from await.
      var id = %DebugNextMicrotaskId();
      SET_PRIVATE(promise, promiseAsyncStackIDSymbol, id);
      %DebugAsyncTaskEvent("enqueueRecurring", id, "async function");
    }
    return promise;
  }
  
  function AsyncFunctionPromiseRelease(promise) {
    if (DEBUG_IS_ACTIVE) {
      // Cancel
      var id = GET_PRIVATE(promise, promiseAsyncStackIDSymbol);
  
      // Don't send invalid events when catch prediction is turned on in
      // the middle of some async operation.
      if (!IS_UNDEFINED(id)) {
        %DebugAsyncTaskEvent("cancel", id, "async function");
      }
      // Pop the Promise under construction in an async function on
      // from catch prediction stack.
      %DebugPopPromise();
    }
  }
  
  %InstallToContext([
    "async_function_await_caught", AsyncFunctionAwaitCaught,
    "async_function_await_uncaught", AsyncFunctionAwaitUncaught,
    "reject_promise_no_debug_event", RejectPromiseNoDebugEvent,
    "async_function_promise_create", AsyncFunctionPromiseCreate,
    "async_function_promise_release", AsyncFunctionPromiseRelease,
  ]);
  
  })
  