Bug 1472342: Part 1 - Properly support iterator getters which need JSContexts. r=bz

The IterableIterator helper currently only supports iterator methods which
return types which are supported by ToJSValue, but do not need a JSContext* to
construct them. That means that getters which need to return native JS objects
or values can't do so safely, or without resorting to hacks.

This patch adds templated helpers which will call a JSContext-accepting,
JS::Value-returning version of the getter methods if they exist, and fall back
to the simpler versions if they don't.

MozReview-Commit-ID: hedZOc3lqR

--HG--
extra : rebase_source : b92cdc3900b3c9bee41836af4d4b9f4e65f3d5f6
This commit is contained in:
Kris Maglione 2018-07-18 13:09:04 -07:00
parent 99d822fb5f
commit 72ae1375d1
2 changed files with 77 additions and 7 deletions

View File

@ -16770,11 +16770,15 @@ class CGIterableMethodGenerator(CGGeneric):
JS::AutoValueArray<3> callArgs(cx);
callArgs[2].setObject(*obj);
JS::Rooted<JS::Value> ignoredReturnVal(cx);
auto GetKeyAtIndex = &${selfType}::GetKeyAtIndex;
auto GetValueAtIndex = &${selfType}::GetValueAtIndex;
for (size_t i = 0; i < self->GetIterableLength(); ++i) {
if (!ToJSValue(cx, self->GetValueAtIndex(i), callArgs[0])) {
if (!CallIterableGetter(cx, GetValueAtIndex, self, i,
callArgs[0])) {
return false;
}
if (!ToJSValue(cx, self->GetKeyAtIndex(i), callArgs[1])) {
if (!CallIterableGetter(cx, GetKeyAtIndex, self, i,
callArgs[1])) {
return false;
}
if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
@ -16783,7 +16787,8 @@ class CGIterableMethodGenerator(CGGeneric):
}
}
""",
ifaceName=descriptor.interface.identifier.name))
ifaceName=descriptor.interface.identifier.name,
selfType=descriptor.nativeType))
return
CGGeneric.__init__(self, fill(
"""

View File

@ -57,6 +57,53 @@ protected:
virtual void TraverseHelper(nsCycleCollectionTraversalCallback& cb) = 0;
};
// Helpers to call iterator getter methods with the correct arguments, depending
// on the types they return, and convert the result to JS::Values.
// Helper for Get[Key,Value]AtIndex(uint32_t) methods, which accept an index and
// return a type supported by ToJSValue.
template <typename T, typename U>
bool
CallIterableGetter(JSContext* aCx, U (T::* aMethod)(uint32_t),
T* aInst, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return ToJSValue(aCx, (aInst->*aMethod)(aIndex), aResult);
}
template <typename T, typename U>
bool
CallIterableGetter(JSContext* aCx, U (T::* aMethod)(uint32_t) const,
const T* aInst, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return ToJSValue(aCx, (aInst->*aMethod)(aIndex), aResult);
}
// Helper for Get[Key,Value]AtIndex(JSContext*, uint32_t, MutableHandleValue)
// methods, which accept a JS context, index, and mutable result value handle,
// and return true on success or false on failure.
template <typename T>
bool
CallIterableGetter(JSContext* aCx,
bool (T::* aMethod)(JSContext*, uint32_t, JS::MutableHandle<JS::Value>),
T* aInst, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return (aInst->*aMethod)(aCx, aIndex, aResult);
}
template <typename T>
bool
CallIterableGetter(JSContext* aCx,
bool (T::* aMethod)(JSContext*, uint32_t, JS::MutableHandle<JS::Value>) const,
const T* aInst, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return (aInst->*aMethod)(aCx, aIndex, aResult);
}
template <typename T>
class IterableIterator final : public IterableIteratorBase
{
@ -78,6 +125,24 @@ public:
MOZ_ASSERT(mWrapFunc);
}
bool
GetKeyAtIndex(JSContext* aCx, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return CallIterableGetter(aCx, &T::GetKeyAtIndex,
mIterableObj.get(),
aIndex, aResult);
}
bool
GetValueAtIndex(JSContext* aCx, uint32_t aIndex,
JS::MutableHandle<JS::Value> aResult)
{
return CallIterableGetter(aCx, &T::GetValueAtIndex,
mIterableObj.get(),
aIndex, aResult);
}
void
Next(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv)
{
@ -89,7 +154,7 @@ public:
switch (mIteratorType) {
case IterableIteratorType::Keys:
{
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &value)) {
if (!GetKeyAtIndex(aCx, mIndex, &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
@ -98,7 +163,7 @@ public:
}
case IterableIteratorType::Values:
{
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
if (!GetValueAtIndex(aCx, mIndex, &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
@ -108,11 +173,11 @@ public:
case IterableIteratorType::Entries:
{
JS::Rooted<JS::Value> key(aCx);
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &key)) {
if (!GetKeyAtIndex(aCx, mIndex, &key)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
if (!GetValueAtIndex(aCx, mIndex, &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}