current commit
261004.7 · deps: update V8 to 15.2.124.38
// Copyright 2018 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.

#ifndef V8_OBJECTS_JS_PROMISE_H_
#define V8_OBJECTS_JS_PROMISE_H_

#include "include/v8-promise.h"
#include "src/base/bit-field.h"
#include "src/handles/handles.h"
#include "src/objects/js-function.h"
#include "src/objects/js-objects.h"
#include "src/objects/promise.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

// Representation of promise objects in the specification. Our layout of
// JSPromise differs a bit from the layout in the specification, for example
// there's only a single list of PromiseReaction objects, instead of separate
// lists for fulfill and reject reactions. The PromiseReaction carries both
// callbacks from the start, and is eventually morphed into the proper kind of
// PromiseReactionJobTask when the JSPromise is settled.
//
// We also overlay the result and reactions fields on the JSPromise, since
// the reactions are only necessary for pending promises, whereas the result
// is only meaningful for settled promises.
V8_OBJECT class JSPromise : public JSObjectWithEmbedderSlots {
 public:
  static constexpr uint32_t kInvalidAsyncTaskId = 0;

  inline Tagged<UnionOf<PromiseReaction, JSAny>> reactions_or_result() const;
  inline void set_reactions_or_result(
      Tagged<UnionOf<PromiseReaction, JSAny>> value,
      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

  inline int flags() const;
  inline void set_flags(int value);

  // [result]: Checks that the promise is settled and returns the result.
  inline Tagged<Object> result() const;

  // [reactions]: Checks that the promise is pending and returns the reactions.
  inline Tagged<Object> reactions() const;

  // [has_handler]: Whether this promise has a reject handler or not.
  DECL_BOOLEAN_ACCESSORS(has_handler)

  // [is_silent]: Whether this promise should cause the debugger to pause when
  // rejected.
  DECL_BOOLEAN_ACCESSORS(is_silent)

  inline bool has_async_task_id() const;
  inline uint32_t async_task_id() const;
  inline void set_async_task_id(uint32_t id);
  // Computes next valid async task ID, silently wrapping around max
  // value and skipping invalid (zero) ID.
  static inline uint32_t GetNextAsyncTaskId(uint32_t current_async_task_id);

  static const char* Status(Promise::PromiseState status);
  V8_EXPORT_PRIVATE Promise::PromiseState status() const;
  void set_status(Promise::PromiseState status);

  // [is_native_resolver_invoked]: This is a part of simpler anti double
  // settlement mechanism for native promises unlike the "promiseOrEmpty"
  // machinery required by the spec for JavaScript promises.
  // https://tc39.es/ecma262/#sec-createresolvingfunctions
  // Returns true if v8::Resolver::Resolve() or Reject() was called for this
  // promise.
  DECL_BOOLEAN_ACCESSORS(is_native_resolver_invoked)

  // https://tc39.es/ecma262/#sec-fulfillpromise
  V8_EXPORT_PRIVATE static Handle<Object> Fulfill(
      DirectHandle<JSPromise> promise, DirectHandle<Object> value);
  // https://tc39.es/ecma262/#sec-rejectpromise
  static Handle<Object> Reject(DirectHandle<JSPromise> promise,
                               DirectHandle<Object> reason,
                               bool debug_event = true);
  // https://tc39.es/ecma262/#sec-promise-resolve-functions
  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Resolve(
      DirectHandle<JSPromise> promise, DirectHandle<Object> resolution);

  // This is intened to be used when we have an array of native promises, so the
  // expectation is a call like PerformPromiseAll([native-promise, ...],
  // %Promise%, NewPromiseCapability(%Promise%), %Promise.resolve%), following
  // the expectation of native promise adoption.
  // If https://github.com/tc39/proposal-defer-import-eval/pull/77/ lands, this
  // function will be the implementation of
  // https://tc39.es/ecma262/#sec-safe-perform-promise-all
  // TODO(caiolima): update this comment after PR decision.
  V8_EXPORT_PRIVATE static MaybeHandle<JSPromise> PerformPromiseAll(
      Isolate* isolate, const DirectHandleVector<JSPromise>& promises);

  // Dispatched behavior.
  DECL_PRINTER(JSPromise)
  DECL_VERIFIER(JSPromise)

  // Flags layout.
  using StatusBits = base::BitField<Promise::PromiseState, 0, 2, uint32_t>;
  using IsNativeResolverInvokedBit = StatusBits::Next<bool, 1>;
  using HasHandlerBit = IsNativeResolverInvokedBit::Next<bool, 1>;
  using IsSilentBit = HasHandlerBit::Next<bool, 1>;
  using AsyncTaskIdBits = IsSilentBit::Next<uint32_t, 26>;

  static_assert(v8::Promise::kPending == 0);
  static_assert(v8::Promise::kFulfilled == 1);
  static_assert(v8::Promise::kRejected == 2);

 public:
  // Smi 0 terminated list of PromiseReaction objects in case the JSPromise
  // was not settled yet, otherwise the result.
  TaggedMember<UnionOf<PromiseReaction, JSAny>> reactions_or_result_;
  // SmiTagged<JSPromiseFlags>.
  TaggedMember<Smi> flags_;

 private:
  // https://tc39.es/ecma262/#sec-triggerpromisereactions
  static Handle<Object> TriggerPromiseReactions(Isolate* isolate,
                                                DirectHandle<Object> reactions,
                                                DirectHandle<Object> argument,
                                                PromiseReaction::Type type);
} V8_OBJECT_END;

V8_OBJECT class JSPromiseConstructor : public JSFunctionWithPrototype {
} V8_OBJECT_END;

}  // namespace internal
}  // namespace v8

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_JS_PROMISE_H_