blob: 366c7c22cdcb6302729be090a0e64a19fa158d84 [file] [log] [blame]
// 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.
#ifndef V8_BUILTINS_BUILTINS_PROMISE_H_
#define V8_BUILTINS_BUILTINS_PROMISE_H_
#include "src/code-stub-assembler.h"
#include "src/contexts.h"
namespace v8 {
namespace internal {
typedef compiler::CodeAssemblerState CodeAssemblerState;
class PromiseBuiltinsAssembler : public CodeStubAssembler {
public:
enum PromiseResolvingFunctionContextSlot {
// The promise which resolve/reject callbacks fulfill. If this is
// undefined, then we've already visited this callback and it
// should be a no-op.
kPromiseSlot = Context::MIN_CONTEXT_SLOTS,
// Whether to trigger a debug event or not. Used in catch
// prediction.
kDebugEventSlot,
kPromiseContextLength,
};
protected:
enum PromiseAllResolveElementContextSlots {
// Whether the resolve callback was already called.
kPromiseAllResolveElementAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS,
// Index into the values array
kPromiseAllResolveElementIndexSlot,
// Remaining elements count (mutable HeapNumber)
kPromiseAllResolveElementRemainingElementsSlot,
// Promise capability from Promise.all
kPromiseAllResolveElementCapabilitySlot,
// Values array from Promise.all
kPromiseAllResolveElementValuesArraySlot,
kPromiseAllResolveElementLength
};
public:
enum FunctionContextSlot {
kCapabilitySlot = Context::MIN_CONTEXT_SLOTS,
kCapabilitiesContextLength,
};
// This is used by the Promise.prototype.finally builtin to store
// onFinally callback and the Promise constructor.
// TODO(gsathya): For native promises we can create a variant of
// this without extra space for the constructor to save memory.
enum PromiseFinallyContextSlot {
kOnFinallySlot = Context::MIN_CONTEXT_SLOTS,
kConstructorSlot,
kPromiseFinallyContextLength,
};
// This is used by the ThenFinally and CatchFinally builtins to
// store the value to return or reason to throw.
enum PromiseValueThunkOrReasonContextSlot {
kValueSlot = Context::MIN_CONTEXT_SLOTS,
kPromiseValueThunkOrReasonContextLength,
};
explicit PromiseBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
// These allocate and initialize a promise with pending state and
// undefined fields.
//
// This uses undefined as the parent promise for the promise init
// hook.
Node* AllocateAndInitJSPromise(Node* context);
// This uses the given parent as the parent promise for the promise
// init hook.
Node* AllocateAndInitJSPromise(Node* context, Node* parent);
// This allocates and initializes a promise with the given state and
// fields.
Node* AllocateAndSetJSPromise(Node* context, v8::Promise::PromiseState status,
Node* result);
Node* AllocatePromiseResolveThenableJobInfo(Node* result, Node* then,
Node* resolve, Node* reject,
Node* context);
std::pair<Node*, Node*> CreatePromiseResolvingFunctions(
Node* promise, Node* native_context, Node* promise_context);
Node* PromiseHasHandler(Node* promise);
Node* CreatePromiseResolvingFunctionsContext(Node* promise, Node* debug_event,
Node* native_context);
Node* CreatePromiseGetCapabilitiesExecutorContext(Node* native_context,
Node* promise_capability);
Node* NewPromiseCapability(Node* context, Node* constructor,
Node* debug_event = nullptr);
protected:
void PromiseInit(Node* promise);
Node* SpeciesConstructor(Node* context, Node* object,
Node* default_constructor);
void PromiseSetHasHandler(Node* promise);
void PromiseSetHandledHint(Node* promise);
void AppendPromiseCallback(int offset, compiler::Node* promise,
compiler::Node* value);
Node* InternalPromiseThen(Node* context, Node* promise, Node* on_resolve,
Node* on_reject);
Node* InternalPerformPromiseThen(Node* context, Node* promise,
Node* on_resolve, Node* on_reject,
Node* deferred_promise,
Node* deferred_on_resolve,
Node* deferred_on_reject);
void InternalResolvePromise(Node* context, Node* promise, Node* result);
void BranchIfFastPath(Node* context, Node* promise, Label* if_isunmodified,
Label* if_ismodified);
void BranchIfFastPath(Node* native_context, Node* promise_fun, Node* promise,
Label* if_isunmodified, Label* if_ismodified);
Node* CreatePromiseContext(Node* native_context, int slots);
void PromiseFulfill(Node* context, Node* promise, Node* result,
v8::Promise::PromiseState status);
void BranchIfAccessCheckFailed(Node* context, Node* native_context,
Node* promise_constructor, Node* executor,
Label* if_noaccess);
void InternalPromiseReject(Node* context, Node* promise, Node* value,
bool debug_event);
void InternalPromiseReject(Node* context, Node* promise, Node* value,
Node* debug_event);
std::pair<Node*, Node*> CreatePromiseFinallyFunctions(Node* on_finally,
Node* constructor,
Node* native_context);
Node* CreateValueThunkFunction(Node* value, Node* native_context);
Node* CreateThrowerFunction(Node* reason, Node* native_context);
Node* PerformPromiseAll(Node* context, Node* constructor, Node* capability,
const IteratorRecord& record, Label* if_exception,
Variable* var_exception);
Node* IncrementSmiCell(Node* cell, Label* if_overflow = nullptr);
Node* DecrementSmiCell(Node* cell);
void SetForwardingHandlerIfTrue(Node* context, Node* condition,
const NodeGenerator& object);
inline void SetForwardingHandlerIfTrue(Node* context, Node* condition,
Node* object) {
return SetForwardingHandlerIfTrue(context, condition,
[object]() -> Node* { return object; });
}
void SetPromiseHandledByIfTrue(Node* context, Node* condition, Node* promise,
const NodeGenerator& handled_by);
Node* PromiseStatus(Node* promise);
void PerformFulfillClosure(Node* context, Node* value, bool should_resolve);
private:
Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status);
Node* AllocateJSPromise(Node* context);
};
} // namespace internal
} // namespace v8
#endif // V8_BUILTINS_BUILTINS_PROMISE_H_