Issue #2089 - Add a PromiseCapability struct, directly initialize dense elements in PerformPromiseAll using NewbornArrayPush

Based-on: m-c 1475678/{8,9}
This commit is contained in:
Martok 2023-01-26 22:25:07 +01:00 • committed by roytam1
commit c0b1bf7e1e
3 changed files with 260 additions and 183 deletions

View file

@ -127,6 +127,67 @@ enum PromiseAllDataHolderSlots {
PromiseAllDataHolderSlots, PromiseAllDataHolderSlots,
}; };
struct PromiseCapability {
JSObject* promise = nullptr;
JSObject* resolve = nullptr;
JSObject* reject = nullptr;
PromiseCapability() = default;
static void trace(PromiseCapability* self, JSTracer* trc) { self->trace(trc); }
void trace(JSTracer* trc);
};
void
PromiseCapability::trace(JSTracer* trc)
{
if (promise)
TraceRoot(trc, &promise, "PromiseCapability::promise");
if (resolve)
TraceRoot(trc, &resolve, "PromiseCapability::resolve");
if (reject)
TraceRoot(trc, &reject, "PromiseCapability::reject");
}
namespace js {
template <typename Wrapper>
class WrappedPtrOperations<PromiseCapability, Wrapper>
{
const PromiseCapability& capability() const { return static_cast<const Wrapper*>(this)->get(); }
public:
HandleObject promise() const {
return HandleObject::fromMarkedLocation(&capability().promise);
}
HandleObject resolve() const {
return HandleObject::fromMarkedLocation(&capability().resolve);
}
HandleObject reject() const {
return HandleObject::fromMarkedLocation(&capability().reject);
}
};
template <typename Wrapper>
class MutableWrappedPtrOperations<PromiseCapability, Wrapper>
: public WrappedPtrOperations<PromiseCapability, Wrapper>
{
PromiseCapability& capability() { return static_cast<Wrapper*>(this)->get(); }
public:
MutableHandleObject promise() {
return MutableHandleObject::fromMarkedLocation(&capability().promise);
}
MutableHandleObject resolve() {
return MutableHandleObject::fromMarkedLocation(&capability().resolve);
}
MutableHandleObject reject() {
return MutableHandleObject::fromMarkedLocation(&capability().reject);
}
};
} // namespace js
class PromiseAllDataHolder : public NativeObject class PromiseAllDataHolder : public NativeObject
{ {
public: public:
@ -366,7 +427,7 @@ static MOZ_MUST_USE bool RunResolutionFunction(JSContext *cx, HandleObject resol
// be tedious, so the check in step 1 and the entirety of step 2 aren't // be tedious, so the check in step 1 and the entirety of step 2 aren't
// included. // included.
static bool static bool
AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, HandleObject reject) AbruptRejectPromise(JSContext* cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
{ {
// Step 1.a. // Step 1.a.
RootedValue reason(cx); RootedValue reason(cx);
@ -381,6 +442,12 @@ AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, Hand
return true; return true;
} }
static bool
AbruptRejectPromise(JSContext* cx, CallArgs& args, Handle<PromiseCapability> capability)
{
return AbruptRejectPromise(cx, args, capability.promise(), capability.reject());
}
enum ReactionRecordSlots { enum ReactionRecordSlots {
// The promise for which this record provides a reaction handler. // The promise for which this record provides a reaction handler.
// Matches the [[Capability]].[[Promise]] field from the spec. // Matches the [[Capability]].[[Promise]] field from the spec.
@ -1039,8 +1106,7 @@ CreatePromiseWithDefaultResolutionFunctions(JSContext* cx, MutableHandleObject r
// ES2016, 25.4.1.5. // ES2016, 25.4.1.5.
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise, NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandle<PromiseCapability> capability,
MutableHandleObject resolve, MutableHandleObject reject,
bool canOmitResolutionFunctions) bool canOmitResolutionFunctions)
{ {
RootedValue cVal(cx, ObjectValue(*C)); RootedValue cVal(cx, ObjectValue(*C));
@ -1065,12 +1131,17 @@ NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
// of the GetCapabilitiesExecutor function, and directly allocate the // of the GetCapabilitiesExecutor function, and directly allocate the
// result promise instead of invoking the Promise constructor. // result promise instead of invoking the Promise constructor.
if (IsNativeFunction(cVal, PromiseConstructor)) { if (IsNativeFunction(cVal, PromiseConstructor)) {
if (canOmitResolutionFunctions) PromiseObject* promise;
promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx)); if (canOmitResolutionFunctions) {
else promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
promise.set(CreatePromiseWithDefaultResolutionFunctions(cx, resolve, reject)); } else {
promise = CreatePromiseWithDefaultResolutionFunctions(cx, capability.resolve(),
capability.reject());
}
if (!promise) if (!promise)
return false; return false;
capability.promise().set(promise);
return true; return true;
} }
@ -1088,7 +1159,7 @@ NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
// Step 6. // Step 6.
FixedConstructArgs<1> cargs(cx); FixedConstructArgs<1> cargs(cx);
cargs[0].setObject(*executor); cargs[0].setObject(*executor);
if (!Construct(cx, cVal, cargs, cVal, promise)) if (!Construct(cx, cVal, cargs, cVal, capability.promise()))
return false; return false;
// Step 7. // Step 7.
@ -1108,8 +1179,8 @@ NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
} }
// Step 9 (well, the equivalent for all of promiseCapabilities' fields.) // Step 9 (well, the equivalent for all of promiseCapabilities' fields.)
resolve.set(&resolveVal.toObject()); capability.resolve().set(&resolveVal.toObject());
reject.set(&rejectVal.toObject()); capability.reject().set(&rejectVal.toObject());
// Step 10. // Step 10.
return true; return true;
@ -1955,10 +2026,9 @@ PromiseObject::createSkippingExecutor(JSContext* cx)
return CreatePromiseObjectWithoutResolutionFunctions(cx); return CreatePromiseObjectWithoutResolutionFunctions(cx);
} }
static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, static MOZ_MUST_USE bool
HandleObject C, HandleObject promiseObj, PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done);
bool* done);
// ES2016, 25.4.4.1. // ES2016, 25.4.4.1.
static bool static bool
@ -1979,28 +2049,26 @@ Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
RootedObject C(cx, &CVal.toObject()); RootedObject C(cx, &CVal.toObject());
// Step 3. // Step 3.
RootedObject resultPromise(cx); Rooted<PromiseCapability> promiseCapability(cx);
RootedObject resolve(cx); if (!NewPromiseCapability(cx, C, &promiseCapability, false))
RootedObject reject(cx);
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
return false; return false;
// Steps 4-5. // Steps 4-5.
JS::ForOfIterator iter(cx); JS::ForOfIterator iter(cx);
if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
if (!iter.valueIsIterable()) { if (!iter.valueIsIterable()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
"Argument of Promise.all"); "Argument of Promise.all");
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
// Step 6 (implicit). // Step 6 (implicit).
// Step 7. // Step 7.
bool done; bool done;
bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done); bool result = PerformPromiseAll(cx, iter, C, promiseCapability, &done);
// Step 8. // Step 8.
if (!result) { if (!result) {
@ -2009,18 +2077,17 @@ Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
iter.closeThrow(); iter.closeThrow();
// Step 8.b. // Step 8.b.
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
// Step 9. // Step 9.
args.rval().setObject(*resultPromise); args.rval().setObject(*promiseCapability.promise());
return true; return true;
} }
static MOZ_MUST_USE bool PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, static MOZ_MUST_USE bool
HandleObject C, HandleObject promiseObj, PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done);
bool* done);
// ES2020 // ES2020
static bool static bool
@ -2036,46 +2103,42 @@ Promise_static_allSettled(JSContext* cx, unsigned argc, Value* vp)
} }
RootedObject C(cx, &CVal.toObject()); RootedObject C(cx, &CVal.toObject());
RootedObject resultPromise(cx); Rooted<PromiseCapability> promiseCapability(cx);
RootedObject resolve(cx); if (!NewPromiseCapability(cx, C, &promiseCapability, false))
RootedObject reject(cx);
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
return false; return false;
JS::ForOfIterator iter(cx); JS::ForOfIterator iter(cx);
if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
if (!iter.valueIsIterable()) { if (!iter.valueIsIterable()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
"Argument of Promise.allSettled"); "Argument of Promise.allSettled");
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
bool done; bool done;
bool result = PerformPromiseAllSettled(cx, iter, C, resultPromise, resolve, reject, &done); bool result = PerformPromiseAllSettled(cx, iter, C, promiseCapability, &done);
if (!result) { if (!result) {
if (!done) if (!done)
iter.closeThrow(); iter.closeThrow();
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
args.rval().setObject(*resultPromise); args.rval().setObject(*promiseCapability.promise());
return true; return true;
} }
static MOZ_MUST_USE bool PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, static MOZ_MUST_USE bool
HandleValue onFulfilled_, HandleValue onRejected_, PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
HandleObject resultPromise, HandleValue onRejected_, Handle<PromiseCapability> resultCapability);
HandleObject resolve, HandleObject reject);
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise, PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve, Handle<PromiseObject*> promiseToResolve,
HandleObject resultPromise, HandleObject resolve, Handle<PromiseCapability> resultCapability);
HandleObject reject);
static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp); static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp);
static bool PromiseAllSettledResolveElementFunction(JSContext* cx, unsigned argc, Value* vp); static bool PromiseAllSettledResolveElementFunction(JSContext* cx, unsigned argc, Value* vp);
@ -2101,10 +2164,8 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
// Step 2 (omitted). // Step 2 (omitted).
// Step 3. // Step 3.
RootedObject resultPromise(cx); Rooted<PromiseCapability> resultCapability(cx);
RootedObject resolve(cx); if (!NewPromiseCapability(cx, C, &resultCapability, false))
RootedObject reject(cx);
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
return nullptr; return nullptr;
// Steps 4-6 (omitted). // Steps 4-6 (omitted).
@ -2127,12 +2188,16 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
// remainingElementsCount (as an integer reserved slot), the array of // remainingElementsCount (as an integer reserved slot), the array of
// values, and the resolve function from our PromiseCapability. // values, and the resolve function from our PromiseCapability.
RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray)); RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, resultPromise, Rooted<PromiseAllDataHolder*> dataHolder(cx);
valuesArrayVal, dataHolder = NewPromiseAllDataHolder(cx, resultCapability.promise(), valuesArrayVal,
resolve)); resultCapability.resolve());
if (!dataHolder) if (!dataHolder)
return nullptr; return nullptr;
// Call PerformPromiseThen with resolve and reject set to nullptr.
Rooted<PromiseCapability> resultCapabilityWithoutResolving(cx);
resultCapabilityWithoutResolving.promise().set(resultCapability.promise());
// Sub-step 5 (inline in loop-header below). // Sub-step 5 (inline in loop-header below).
// Sub-step 6. // Sub-step 6.
@ -2166,7 +2231,7 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
// Step q, very roughly. // Step q, very roughly.
RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc)); RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
RootedValue rejectFunVal(cx, ObjectValue(*reject)); RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
Rooted<PromiseObject*> nextPromise(cx); Rooted<PromiseObject*> nextPromise(cx);
// GetWaitForAllPromise is used internally only and must not // GetWaitForAllPromise is used internally only and must not
@ -2178,7 +2243,7 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
nextPromise = &UncheckedUnwrap(nextPromiseObj)->as<PromiseObject>(); nextPromise = &UncheckedUnwrap(nextPromiseObj)->as<PromiseObject>();
if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal, if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal,
resultPromise, nullptr, nullptr)) resultCapabilityWithoutResolving))
{ {
return nullptr; return nullptr;
} }
@ -2193,7 +2258,7 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
// Sub-step d.iii-iv. // Sub-step d.iii-iv.
if (remainingCount == 0) { if (remainingCount == 0) {
RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray)); RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
if (!ResolvePromiseInternal(cx, resultPromise, valuesArrayVal)) if (!ResolvePromiseInternal(cx, resultCapability.promise(), valuesArrayVal))
return nullptr; return nullptr;
} }
} }
@ -2201,7 +2266,7 @@ js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
// Step 8 (omitted). // Step 8 (omitted).
// Step 9. // Step 9.
return resultPromise; return resultCapability.promise();
} }
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
@ -2241,11 +2306,12 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res
// ES2016, 25.4.4.1.1. // ES2016, 25.4.4.1.1.
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject promiseObj, HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done)
bool* done)
{ {
*done = false; *done = false;
HandleObject promiseObj = resultCapability.promise();
// Step 1. // Step 1.
MOZ_ASSERT(C->isConstructor()); MOZ_ASSERT(C->isConstructor());
RootedValue CVal(cx, ObjectValue(*C)); RootedValue CVal(cx, ObjectValue(*C));
@ -2272,30 +2338,38 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// those are happening over Xrays anyway, which means they get the // those are happening over Xrays anyway, which means they get the
// canonical "then" function and content can't see our // canonical "then" function and content can't see our
// PromiseAllResolveElement. // PromiseAllResolveElement.
RootedObject valuesArray(cx); RootedArrayObject valuesArray(cx);
RootedValue valuesArrayVal(cx);
if (IsWrapper(promiseObj)) { if (IsWrapper(promiseObj)) {
JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj); JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj);
MOZ_ASSERT(unwrappedPromiseObj); MOZ_ASSERT(unwrappedPromiseObj);
AutoCompartment ac(cx, unwrappedPromiseObj); {
valuesArray = NewDenseFullyAllocatedArray(cx, 0); AutoCompartment ac(cx, unwrappedPromiseObj);
} else { valuesArray = NewDenseEmptyArray(cx);
valuesArray = NewDenseFullyAllocatedArray(cx, 0); if (!valuesArray)
} return false;
if (!valuesArray) }
return false;
RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray)); valuesArrayVal.setObject(*valuesArray);
if (!cx->compartment()->wrap(cx, &valuesArrayVal)) if (!cx->compartment()->wrap(cx, &valuesArrayVal))
return false; return false;
} else {
valuesArray = NewDenseEmptyArray(cx);
if (!valuesArray)
return false;
valuesArrayVal.setObject(*valuesArray);
}
// Step 4. // Step 4.
// Create our data holder that holds all the things shared across // Create our data holder that holds all the things shared across
// every step of the iterator. In particular, this holds the // every step of the iterator. In particular, this holds the
// remainingElementsCount (as an integer reserved slot), the array of // remainingElementsCount (as an integer reserved slot), the array of
// values, and the resolve function from our PromiseCapability. // values, and the resolve function from our PromiseCapability.
Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, promiseObj, Rooted<PromiseAllDataHolder*> dataHolder(cx);
valuesArrayVal, resolve)); dataHolder = NewPromiseAllDataHolder(cx, promiseObj, valuesArrayVal,
resultCapability.resolve());
if (!dataHolder) if (!dataHolder)
return false; return false;
@ -2305,8 +2379,7 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// Step 6. // Step 6.
RootedValue nextValue(cx); RootedValue nextValue(cx);
RootedValue nextPromise(cx); RootedValue nextPromise(cx);
RootedId indexId(cx); RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
RootedValue rejectFunVal(cx, ObjectValue(*reject));
RootedValue resolveFunVal(cx); RootedValue resolveFunVal(cx);
RootedValue staticResolve(cx); RootedValue staticResolve(cx);
@ -2329,8 +2402,8 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// Steps d.iii-iv. // Steps d.iii-iv.
if (remainingCount == 0) { if (remainingCount == 0) {
return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode, return RunResolutionFunction(cx, resultCapability.resolve(), valuesArrayVal,
promiseObj); ResolveMode, promiseObj);
} }
// We're all set for now! // We're all set for now!
@ -2342,8 +2415,8 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// mostly do this for performance; we could go ahead and do the define via // mostly do this for performance; we could go ahead and do the define via
// a cross-compartment proxy instead... // a cross-compartment proxy instead...
AutoCompartment ac(cx, valuesArray); AutoCompartment ac(cx, valuesArray);
indexId = INT_TO_JSID(index);
if (!DefineProperty(cx, valuesArray, indexId, UndefinedHandleValue)) if (!NewbornArrayPush(cx, valuesArray, UndefinedValue()))
return false; return false;
} }
@ -2389,35 +2462,41 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject promiseObj, HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done)
bool* done)
{ {
*done = false; *done = false;
RootedObject unwrappedPromiseObj(cx); HandleObject promiseObj = resultCapability.promise();
if (IsWrapper(promiseObj)) {
unwrappedPromiseObj = CheckedUnwrap(promiseObj);
MOZ_ASSERT(unwrappedPromiseObj);
}
RootedValue CVal(cx, ObjectValue(*C)); RootedValue CVal(cx, ObjectValue(*C));
RootedObject valuesArray(cx); RootedArrayObject valuesArray(cx);
if (unwrappedPromiseObj) { RootedValue valuesArrayVal(cx);
JSAutoCompartment ac(cx, unwrappedPromiseObj); if (IsWrapper(promiseObj)) {
valuesArray = NewDenseFullyAllocatedArray(cx, 0); JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj);
MOZ_ASSERT(unwrappedPromiseObj);
{
AutoCompartment ac(cx, unwrappedPromiseObj);
valuesArray = NewDenseEmptyArray(cx);
if (!valuesArray)
return false;
}
valuesArrayVal.setObject(*valuesArray);
if (!cx->compartment()->wrap(cx, &valuesArrayVal))
return false;
} else { } else {
valuesArray = NewDenseFullyAllocatedArray(cx, 0); valuesArray = NewDenseEmptyArray(cx);
if (!valuesArray)
return false;
valuesArrayVal.setObject(*valuesArray);
} }
if (!valuesArray)
return false;
RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray)); Rooted<PromiseAllDataHolder*> dataHolder(cx);
if (!cx->compartment()->wrap(cx, &valuesArrayVal)) dataHolder = NewPromiseAllDataHolder(cx, promiseObj, valuesArrayVal,
return false; resultCapability.resolve());
Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, promiseObj,
valuesArrayVal, resolve));
if (!dataHolder) if (!dataHolder)
return false; return false;
RootedValue dataHolderVal(cx, ObjectValue(*dataHolder)); RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
@ -2425,7 +2504,6 @@ PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, HandleObjec
uint32_t index = 0; uint32_t index = 0;
RootedValue nextValue(cx); RootedValue nextValue(cx);
RootedId indexId(cx);
while (true) { while (true) {
if (!iterator.next(&nextValue, done)) { if (!iterator.next(&nextValue, done)) {
@ -2436,16 +2514,16 @@ PerformPromiseAllSettled(JSContext *cx, JS::ForOfIterator& iterator, HandleObjec
if (*done) { if (*done) {
int32_t remainingCount = dataHolder->decreaseRemainingCount(); int32_t remainingCount = dataHolder->decreaseRemainingCount();
if (remainingCount == 0) { if (remainingCount == 0) {
return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode, return RunResolutionFunction(cx, resultCapability.resolve(), valuesArrayVal,
promiseObj); ResolveMode, promiseObj);
} }
return true; return true;
} }
{ // Scoped for AutoCompartment { // Scoped for AutoCompartment
JSAutoCompartment ac(cx, valuesArray); JSAutoCompartment ac(cx, valuesArray);
indexId = INT_TO_JSID(index);
if (!DefineProperty(cx, valuesArray, indexId, UndefinedHandleValue)) if (!NewbornArrayPush(cx, valuesArray, UndefinedValue()))
return false; return false;
} }
@ -2736,10 +2814,9 @@ PromiseAllSettledRejectElementFunction(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, static MOZ_MUST_USE bool
HandleObject C, HandleObject promiseObj, PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done);
bool* done);
// ES2016, 25.4.4.3. // ES2016, 25.4.4.3.
static bool static bool
@ -2760,28 +2837,26 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
RootedObject C(cx, &CVal.toObject()); RootedObject C(cx, &CVal.toObject());
// Step 3. // Step 3.
RootedObject resultPromise(cx); Rooted<PromiseCapability> promiseCapability(cx);
RootedObject resolve(cx); if (!NewPromiseCapability(cx, C, &promiseCapability, false))
RootedObject reject(cx);
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
return false; return false;
// Steps 4-5. // Steps 4-5.
JS::ForOfIterator iter(cx); JS::ForOfIterator iter(cx);
if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
if (!iter.valueIsIterable()) { if (!iter.valueIsIterable()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
"Argument of Promise.race"); "Argument of Promise.race");
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
// Step 6 (implicit). // Step 6 (implicit).
// Step 7. // Step 7.
bool done; bool done;
bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done); bool result = PerformPromiseRace(cx, iter, C, promiseCapability, &done);
// Step 8. // Step 8.
if (!result) { if (!result) {
@ -2790,19 +2865,18 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
iter.closeThrow(); iter.closeThrow();
// Step 8.b. // Step 8.b.
return AbruptRejectPromise(cx, args, resultPromise, reject); return AbruptRejectPromise(cx, args, promiseCapability);
} }
// Step 9. // Step 9.
args.rval().setObject(*resultPromise); args.rval().setObject(*promiseCapability.promise());
return true; return true;
} }
// ES2016, 25.4.4.3.1. // ES2016, 25.4.4.3.1.
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
HandleObject promiseObj, HandleObject resolve, HandleObject reject, Handle<PromiseCapability> resultCapability, bool* done)
bool* done)
{ {
*done = false; *done = false;
MOZ_ASSERT(C->isConstructor()); MOZ_ASSERT(C->isConstructor());
@ -2811,11 +2885,16 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// BlockOnPromise fast path requires the passed onFulfilled function // BlockOnPromise fast path requires the passed onFulfilled function
// doesn't return an object value, because otherwise the skipped promise // doesn't return an object value, because otherwise the skipped promise
// creation is detectable due to missing property lookups. // creation is detectable due to missing property lookups.
bool isDefaultResolveFn = IsNativeFunction(resolve, ResolvePromiseFunction); bool isDefaultResolveFn = IsNativeFunction(resultCapability.resolve(),
ResolvePromiseFunction);
HandleObject promiseObj = resultCapability.promise();
RootedValue resolveFunVal(cx, ObjectValue(*resultCapability.resolve()));
RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
RootedValue nextValue(cx); RootedValue nextValue(cx);
RootedValue resolveFunVal(cx, ObjectValue(*resolve)); RootedValue nextPromise(cx);
RootedValue rejectFunVal(cx, ObjectValue(*reject)); RootedValue staticResolve(cx);
while (true) { while (true) {
// Steps a-c, e-g. // Steps a-c, e-g.
@ -2838,8 +2917,6 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
// Step h. // Step h.
// Sadly, because someone could have overridden // Sadly, because someone could have overridden
// "resolve" on the canonical Promise constructor. // "resolve" on the canonical Promise constructor.
RootedValue nextPromise(cx);
RootedValue staticResolve(cx);
if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve)) if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
return false; return false;
@ -2902,21 +2979,19 @@ CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue ar
} }
// Step 4 of Resolve, 3 of Reject. // Step 4 of Resolve, 3 of Reject.
RootedObject promise(cx); Rooted<PromiseCapability> capability(cx);
RootedObject resolveFun(cx); if (!NewPromiseCapability(cx, C, &capability, true))
RootedObject rejectFun(cx);
if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
return nullptr; return nullptr;
// Step 5 of Resolve, 4 of Reject. // Step 5 of Resolve, 4 of Reject.
if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode, if (!RunResolutionFunction(cx, mode == ResolveMode ? capability.resolve() : capability.reject(),
promise)) argVal, mode, capability.promise()))
{ {
return nullptr; return nullptr;
} }
// Step 6 of Resolve, 4 of Reject. // Step 6 of Resolve, 4 of Reject.
return promise; return capability.promise();
} }
MOZ_MUST_USE JSObject* MOZ_MUST_USE JSObject*
@ -3004,18 +3079,22 @@ enum class IncumbentGlobalObject {
}; };
static PromiseReactionRecord* static PromiseReactionRecord*
NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfilled, NewReactionRecord(JSContext* cx, Handle<PromiseCapability> resultCapability,
HandleValue onRejected, HandleObject resolve, HandleObject reject, HandleValue onFulfilled, HandleValue onRejected,
IncumbentGlobalObject incumbentGlobalObjectOption) IncumbentGlobalObject incumbentGlobalObjectOption)
{ {
// Either of the following conditions must be met: // Either of the following conditions must be met:
// * resultPromise is a PromiseObject // * resultCapability.promise is a PromiseObject
// * resolve and reject are callable // * resultCapability.resolve and resultCapability.resolve are callable
// except for Async Generator, there resultPromise can be nullptr. // except for Async Generator, there resultPromise can be nullptr.
MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), resolve); #ifdef DEBUG
MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(resolve)); if (resultCapability.promise() && !resultCapability.promise()->is<PromiseObject>()) {
MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), reject); MOZ_ASSERT(resultCapability.resolve());
MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(reject)); MOZ_ASSERT(IsCallable(resultCapability.resolve()));
MOZ_ASSERT(resultCapability.reject());
MOZ_ASSERT(IsCallable(resultCapability.reject()));
}
#endif
// Ensure the onFulfilled handler has the expected type. // Ensure the onFulfilled handler has the expected type.
MOZ_ASSERT(onFulfilled.isInt32() || onFulfilled.isObjectOrNull()); MOZ_ASSERT(onFulfilled.isInt32() || onFulfilled.isObjectOrNull());
@ -3042,19 +3121,22 @@ NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfi
if (!reaction) if (!reaction)
return nullptr; return nullptr;
assertSameCompartment(cx, resultPromise); assertSameCompartment(cx, resultCapability.promise());
assertSameCompartment(cx, onFulfilled); assertSameCompartment(cx, onFulfilled);
assertSameCompartment(cx, onRejected); assertSameCompartment(cx, onRejected);
assertSameCompartment(cx, resolve); assertSameCompartment(cx, resultCapability.resolve());
assertSameCompartment(cx, reject); assertSameCompartment(cx, resultCapability.reject());
assertSameCompartment(cx, incumbentGlobalObject); assertSameCompartment(cx, incumbentGlobalObject);
reaction->setFixedSlot(ReactionRecordSlot_Promise, ObjectOrNullValue(resultPromise)); reaction->setFixedSlot(ReactionRecordSlot_Promise,
ObjectOrNullValue(resultCapability.promise()));
reaction->setFixedSlot(ReactionRecordSlot_Flags, Int32Value(0)); reaction->setFixedSlot(ReactionRecordSlot_Flags, Int32Value(0));
reaction->setFixedSlot(ReactionRecordSlot_OnFulfilled, onFulfilled); reaction->setFixedSlot(ReactionRecordSlot_OnFulfilled, onFulfilled);
reaction->setFixedSlot(ReactionRecordSlot_OnRejected, onRejected); reaction->setFixedSlot(ReactionRecordSlot_OnRejected, onRejected);
reaction->setFixedSlot(ReactionRecordSlot_Resolve, ObjectOrNullValue(resolve)); reaction->setFixedSlot(ReactionRecordSlot_Resolve,
reaction->setFixedSlot(ReactionRecordSlot_Reject, ObjectOrNullValue(reject)); ObjectOrNullValue(resultCapability.resolve()));
reaction->setFixedSlot(ReactionRecordSlot_Reject,
ObjectOrNullValue(resultCapability.reject()));
reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject, reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject,
ObjectOrNullValue(incumbentGlobalObject)); ObjectOrNullValue(incumbentGlobalObject));
@ -3070,8 +3152,7 @@ IsPromiseSpecies(JSContext* cx, JSFunction* species)
static bool static bool
PromiseThenNewPromiseCapability(JSContext* cx, HandleObject promiseObj, PromiseThenNewPromiseCapability(JSContext* cx, HandleObject promiseObj,
CreateDependentPromise createDependent, CreateDependentPromise createDependent,
MutableHandleObject resultPromise, MutableHandle<PromiseCapability> resultCapability)
MutableHandleObject resolve, MutableHandleObject reject)
{ {
if (createDependent != CreateDependentPromise::Never) { if (createDependent != CreateDependentPromise::Never) {
// Step 3. // Step 3.
@ -3083,7 +3164,7 @@ PromiseThenNewPromiseCapability(JSContext* cx, HandleObject promiseObj,
!IsNativeFunction(C, PromiseConstructor)) !IsNativeFunction(C, PromiseConstructor))
{ {
// Step 4. // Step 4.
if (!NewPromiseCapability(cx, C, resultPromise, resolve, reject, true)) if (!NewPromiseCapability(cx, C, resultCapability, true))
return false; return false;
} }
} }
@ -3103,21 +3184,16 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
return false; return false;
} }
RootedObject resultPromise(cx); // Steps 3-4.
RootedObject resolve(cx); Rooted<PromiseCapability> resultCapability(cx);
RootedObject reject(cx); if (!PromiseThenNewPromiseCapability(cx, promiseObj, createDependent, &resultCapability))
if (!PromiseThenNewPromiseCapability(cx, promiseObj, createDependent, &resultPromise,
&resolve, &reject))
{
return false; return false;
}
// Step 5. // Step 5.
if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject)) if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultCapability))
return false; return false;
dependent.set(resultPromise); dependent.set(resultCapability.promise());
return true; return true;
} }
@ -3128,18 +3204,15 @@ OriginalPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> p
assertSameCompartment(cx, promise); assertSameCompartment(cx, promise);
// Steps 3-4. // Steps 3-4.
RootedObject resultPromise(cx); Rooted<PromiseCapability> resultCapability(cx);
RootedObject resolve(cx);
RootedObject reject(cx);
if (!PromiseThenNewPromiseCapability(cx, promise, CreateDependentPromise::SkipIfCtorUnobservable, if (!PromiseThenNewPromiseCapability(cx, promise, CreateDependentPromise::SkipIfCtorUnobservable,
&resultPromise, &resolve, &reject)) &resultCapability))
{ {
return false; return false;
} }
// Step 5. // Step 5.
return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve, resultPromise, return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve, resultCapability);
resolve, reject);
} }
static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx, static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
@ -3218,9 +3291,10 @@ InternalAwait(JSContext* cx, HandleValue value, HandleObject resultPromise,
return false; return false;
// Steps 7-8. // Steps 7-8.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, Rooted<PromiseCapability> resultCapability(cx);
resultCapability.promise().set(resultPromise);
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
onFulfilled, onRejected, onFulfilled, onRejected,
nullptr, nullptr,
IncumbentGlobalObject::Yes)); IncumbentGlobalObject::Yes));
if (!reaction) if (!reaction)
return false; return false;
@ -3797,8 +3871,7 @@ Promise_then(JSContext* cx, unsigned argc, Value* vp)
// ES2016, 25.4.5.3.1. // ES2016, 25.4.5.3.1.
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_, PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
HandleValue onRejected_, HandleObject resultPromise, HandleValue onRejected_, Handle<PromiseCapability> resultCapability)
HandleObject resolve, HandleObject reject)
{ {
// Step 1 (implicit). // Step 1 (implicit).
// Step 2 (implicit). // Step 2 (implicit).
@ -3814,9 +3887,8 @@ PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue on
onRejected = Int32Value(PromiseHandlerThrower); onRejected = Int32Value(PromiseHandlerThrower);
// Step 7. // Step 7.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
onFulfilled, onRejected, onFulfilled, onRejected,
resolve, reject,
IncumbentGlobalObject::Yes)); IncumbentGlobalObject::Yes));
if (!reaction) if (!reaction)
return false; return false;
@ -3827,8 +3899,7 @@ PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue on
static MOZ_MUST_USE bool static MOZ_MUST_USE bool
PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise, PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve, Handle<PromiseObject*> promiseToResolve,
HandleObject resultPromise, HandleObject resolve, Handle<PromiseCapability> resultCapability)
HandleObject reject)
{ {
// Step 1 (implicit). // Step 1 (implicit).
// Step 2 (implicit). // Step 2 (implicit).
@ -3840,9 +3911,8 @@ PerformPromiseThenWithoutSettleHandlers(JSContext* cx, Handle<PromiseObject*> pr
HandleValue onRejected = NullHandleValue; HandleValue onRejected = NullHandleValue;
// Step 7. // Step 7.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultCapability,
onFulfilled, onRejected, onFulfilled, onRejected,
resolve, reject,
IncumbentGlobalObject::Yes)); IncumbentGlobalObject::Yes));
if (!reaction) if (!reaction)
return false; return false;
@ -3929,9 +3999,7 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
if (!C) if (!C)
return false; return false;
RootedObject resultPromise(cx); Rooted<PromiseCapability> resultCapability(cx);
RootedObject resolveFun(cx);
RootedObject rejectFun(cx);
// By default, the blocked promise is added as an extra entry to the // By default, the blocked promise is added as an extra entry to the
// rejected promises list. // rejected promises list.
@ -3951,21 +4019,18 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
!PromiseHasAnyFlag(blockedPromise_->as<PromiseObject>(), !PromiseHasAnyFlag(blockedPromise_->as<PromiseObject>(),
PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS)) PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS))
{ {
resultPromise.set(blockedPromise_); resultCapability.promise().set(blockedPromise_);
addToDependent = false; addToDependent = false;
} else { } else {
// 25.4.5.3., step 4. // 25.4.5.3., step 4.
if (!NewPromiseCapability(cx, C, &resultPromise, &resolveFun, &rejectFun, true)) if (!NewPromiseCapability(cx, C, &resultCapability, true))
return false; return false;
} }
// 25.4.5.3., step 5. // 25.4.5.3., step 5.
Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>(); Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>();
if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultCapability))
resolveFun, rejectFun))
{
return false; return false;
}
if (!addToDependent) if (!addToDependent)
return true; return true;
@ -4098,9 +4163,12 @@ AddDummyPromiseReactionForDebugger(JSContext* cx, Handle<PromiseObject*> promise
if (promise->state() != JS::PromiseState::Pending) if (promise->state() != JS::PromiseState::Pending)
return true; return true;
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, dependentPromise, // Leave resolve and reject as null.
Rooted<PromiseCapability> capability(cx);
capability.promise().set(dependentPromise);
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, capability,
NullHandleValue, NullHandleValue, NullHandleValue, NullHandleValue,
nullptr, nullptr,
IncumbentGlobalObject::No)); IncumbentGlobalObject::No));
if (!reaction) if (!reaction)
return false; return false;

View file

@ -64,13 +64,19 @@ NativeObject::clearShouldConvertDoubleElements()
} }
inline void inline void
NativeObject::setDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val) NativeObject::addDenseElementType(ExclusiveContext* cx, uint32_t index, const Value& val)
{ {
// Avoid a slow AddTypePropertyId call if the type is the same as the type // Avoid a slow AddTypePropertyId call if the type is the same as the type
// of the previous element. // of the previous element.
TypeSet::Type thisType = TypeSet::GetValueType(val); TypeSet::Type thisType = TypeSet::GetValueType(val);
if (index == 0 || TypeSet::GetValueType(elements_[index - 1]) != thisType) if (index == 0 || TypeSet::GetValueType(elements_[index - 1]) != thisType)
AddTypePropertyId(cx, this, JSID_VOID, thisType); AddTypePropertyId(cx, this, JSID_VOID, thisType);
}
inline void
NativeObject::setDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val)
{
addDenseElementType(cx, index, val);
setDenseElementMaybeConvertDouble(index, val); setDenseElementMaybeConvertDouble(index, val);
} }
@ -78,10 +84,9 @@ inline void
NativeObject::initDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val) NativeObject::initDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val)
{ {
MOZ_ASSERT(!shouldConvertDoubleElements()); MOZ_ASSERT(!shouldConvertDoubleElements());
if (val.isMagic(JS_ELEMENTS_HOLE)) MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));
markDenseElementsNotPacked(cx);
else addDenseElementType(cx, index, val);
AddTypePropertyId(cx, this, JSID_VOID, val);
initDenseElement(index, val); initDenseElement(index, val);
} }

View file

@ -1076,6 +1076,10 @@ class NativeObject : public ShapedObject
setDenseElement(index, val); setDenseElement(index, val);
} }
private:
inline void addDenseElementType(ExclusiveContext* cx, uint32_t index, const Value& val);
public:
inline void setDenseElementWithType(ExclusiveContext* cx, uint32_t index, inline void setDenseElementWithType(ExclusiveContext* cx, uint32_t index,
const Value& val); const Value& val);
inline void initDenseElementWithType(ExclusiveContext* cx, uint32_t index, inline void initDenseElementWithType(ExclusiveContext* cx, uint32_t index,