blob: 0b5a2177a24f84f37d095a0ccf459d8efba63944 [file] [log] [blame]
// 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 ScriptPromiseProperty_h
#define ScriptPromiseProperty_h
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromisePropertyBase.h"
#include "bindings/core/v8/ToV8.h"
#include "wtf/Noncopyable.h"
#include "wtf/PassRefPtr.h"
namespace blink {
class ExecutionContext;
// ScriptPromiseProperty is a helper for implementing a DOM method or
// attribute whose value is a Promise, and the same Promise must be
// returned each time.
//
// ScriptPromiseProperty does not keep Promises or worlds alive to
// deliver Promise resolution/rejection to them; the Promise
// resolution/rejections are delivered if the holder's wrapper is
// alive. This is achieved by keeping a weak reference from
// ScriptPromiseProperty to the holder's wrapper, and references in
// hidden values from the wrapper to the promise and resolver
// (coincidentally the Resolver and Promise may be the same object,
// but that is an implementation detail of v8.)
//
// ----> Resolver
// /
// ScriptPromiseProperty - - -> Holder Wrapper ----> Promise
//
// To avoid exposing the action of the garbage collector to script,
// you should keep the wrapper alive as long as a promise may be
// settled.
//
// To avoid clobbering hidden values, a holder should only have one
// ScriptPromiseProperty object for a given name at a time. See reset.
template <typename HolderType, typename ResolvedType, typename RejectedType>
class ScriptPromiseProperty : public ScriptPromisePropertyBase {
WTF_MAKE_NONCOPYABLE(ScriptPromiseProperty);
public:
// Creates a ScriptPromiseProperty that will create Promises in
// the specified ExecutionContext for a property of 'holder'
// (typically ScriptPromiseProperty should be a member of the
// property holder).
//
// When implementing a ScriptPromiseProperty add the property name
// to ScriptPromiseProperties.h and pass
// ScriptPromiseProperty::Foo to create. The name must be unique
// per kind of holder.
template <typename PassHolderType>
ScriptPromiseProperty(ExecutionContext*, PassHolderType, Name);
~ScriptPromiseProperty() override {}
template <typename PassResolvedType>
void resolve(PassResolvedType);
template <typename PassRejectedType>
void reject(PassRejectedType);
// Resets this property by unregistering the Promise property from the
// holder wrapper. Resets the internal state to Pending and clears the
// resolved and the rejected values.
// This method keeps the holder object and the property name.
void reset();
DECLARE_VIRTUAL_TRACE();
private:
v8::Local<v8::Object> holder(v8::Isolate*,
v8::Local<v8::Object> creationContext) override;
v8::Local<v8::Value> resolvedValue(
v8::Isolate*,
v8::Local<v8::Object> creationContext) override;
v8::Local<v8::Value> rejectedValue(
v8::Isolate*,
v8::Local<v8::Object> creationContext) override;
HolderType m_holder;
ResolvedType m_resolved;
RejectedType m_rejected;
};
template <typename HolderType, typename ResolvedType, typename RejectedType>
template <typename PassHolderType>
ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::
ScriptPromiseProperty(ExecutionContext* executionContext,
PassHolderType holder,
Name name)
: ScriptPromisePropertyBase(executionContext, name), m_holder(holder) {}
template <typename HolderType, typename ResolvedType, typename RejectedType>
template <typename PassResolvedType>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::resolve(
PassResolvedType value) {
if (getState() != Pending) {
ASSERT_NOT_REACHED();
return;
}
if (!getExecutionContext() ||
getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_resolved = value;
resolveOrReject(Resolved);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
template <typename PassRejectedType>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::reject(
PassRejectedType value) {
if (getState() != Pending) {
ASSERT_NOT_REACHED();
return;
}
if (!getExecutionContext() ||
getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_rejected = value;
resolveOrReject(Rejected);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
v8::Local<v8::Object>
ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::holder(
v8::Isolate* isolate,
v8::Local<v8::Object> creationContext) {
v8::Local<v8::Value> value = toV8(m_holder, creationContext, isolate);
if (value.IsEmpty())
return v8::Local<v8::Object>();
return value.As<v8::Object>();
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
v8::Local<v8::Value>
ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::resolvedValue(
v8::Isolate* isolate,
v8::Local<v8::Object> creationContext) {
ASSERT(getState() == Resolved);
return toV8(m_resolved, creationContext, isolate);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
v8::Local<v8::Value>
ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::rejectedValue(
v8::Isolate* isolate,
v8::Local<v8::Object> creationContext) {
ASSERT(getState() == Rejected);
return toV8(m_rejected, creationContext, isolate);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::reset() {
resetBase();
m_resolved = ResolvedType();
m_rejected = RejectedType();
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::trace(
Visitor* visitor) {
traceImpl(visitor);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::trace(
InlinedGlobalMarkingVisitor visitor) {
traceImpl(visitor);
}
template <typename HolderType, typename ResolvedType, typename RejectedType>
template <typename VisitorDispatcher>
void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::traceImpl(
VisitorDispatcher visitor) {
TraceIfNeeded<HolderType>::trace(visitor, m_holder);
TraceIfNeeded<ResolvedType>::trace(visitor, m_resolved);
TraceIfNeeded<RejectedType>::trace(visitor, m_rejected);
ScriptPromisePropertyBase::trace(visitor);
}
} // namespace blink
#endif // ScriptPromiseProperty_h