/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects.promise;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.types.ScriptObject;
/**
*
*/
public final class FinalizablePromiseObject extends PromiseObject {
private boolean trackRejection = true;
private RejectReason rejectReason;
public FinalizablePromiseObject(Realm realm) {
super(realm);
rejectReason = new RejectReason(realm);
}
@Override
void notifyReject(Object reason) {
if (trackRejection) {
rejectReason.set(reason);
}
}
@Override
void notifyRejectReaction(PromiseReaction reaction) {
assert getState() == State.Pending || getState() == State.Rejected;
if (reaction.getType() != PromiseReaction.Type.Thrower) {
trackRejection = false;
rejectReason.clear();
} else {
ScriptObject promise = reaction.getCapabilities().getPromise();
if (promise instanceof FinalizablePromiseObject) {
FinalizablePromiseObject promiseObject = (FinalizablePromiseObject) promise;
if (promiseObject.getState() == State.Pending) {
// TODO: This is not quite correct when `promiseObject` is rejected on its own.
// Don't track rejection for dependent promises.
promiseObject.trackRejection = false;
promiseObject.rejectReason = rejectReason;
}
}
}
}
/**
* Holder object for promise rejection reasons.
*/
private static final class RejectReason {
private final Realm realm;
private boolean valueSet;
private Object value;
RejectReason(Realm realm) {
this.realm = realm;
}
private void setValue(Object value) {
this.value = value;
this.valueSet = true;
}
void set(Object reason) {
if (!valueSet) {
setValue(reason);
}
}
void clear() {
setValue(null);
}
@Override
protected void finalize() throws Throwable {
if (value != null) {
realm.enqueueUnhandledPromiseRejection(value);
}
super.finalize();
}
}
}