diff options
author | Moonchild <mcwerewolf@gmail.com> | 2018-03-16 08:36:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-16 08:36:30 +0100 |
commit | 11bdaa144d8a38ecd897dde278cb1db9b8313961 (patch) | |
tree | 1ca375db23843dcd4c593bcb28d7173856bddc10 /js/src/builtin | |
parent | 0d3ee51ad2d61bffba14232b2df913d3a773d771 (diff) | |
parent | 114794557687aebca601c38ba0f0a52a43b44d4a (diff) | |
download | UXP-11bdaa144d8a38ecd897dde278cb1db9b8313961.tar UXP-11bdaa144d8a38ecd897dde278cb1db9b8313961.tar.gz UXP-11bdaa144d8a38ecd897dde278cb1db9b8313961.tar.lz UXP-11bdaa144d8a38ecd897dde278cb1db9b8313961.tar.xz UXP-11bdaa144d8a38ecd897dde278cb1db9b8313961.zip |
Merge pull request #66 from janekptacijarabaci/js_iterable_closures_1
Close iterator after error in: Map, Set, WeakMap, WeakSet, Array.from, Promise.{all,race}
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/Array.js | 46 | ||||
-rw-r--r-- | js/src/builtin/Map.js | 11 | ||||
-rw-r--r-- | js/src/builtin/Promise.cpp | 53 | ||||
-rw-r--r-- | js/src/builtin/Set.js | 7 | ||||
-rw-r--r-- | js/src/builtin/Utilities.js | 23 | ||||
-rw-r--r-- | js/src/builtin/WeakMap.js | 11 | ||||
-rw-r--r-- | js/src/builtin/WeakSet.js | 7 |
7 files changed, 121 insertions, 37 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 54b47b72f..5ab0b71be 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -784,7 +784,7 @@ function ArrayKeys() { return CreateArrayIterator(this, ITEM_KIND_KEY); } -// ES6 draft rev31 (2015/01/15) 22.1.2.1 Array.from(source[, mapfn[, thisArg]]). +// ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1 function ArrayFrom(items, mapfn=undefined, thisArg=undefined) { // Step 1. var C = this; @@ -795,43 +795,61 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) { ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn)); var T = thisArg; - // Steps 4-5. + // Step 4. var usingIterator = GetMethod(items, std_iterator); - // Step 6. + // Step 5. if (usingIterator !== undefined) { - // Steps 6.a-c. + // Steps 5.a-c. var A = IsConstructor(C) ? new C() : []; - // Steps 6.d-e. + // Step 5.c. var iterator = GetIterator(items, usingIterator); - // Step 6.f. + // Step 5.d. var k = 0; - // Step 6.g. + // Step 5.e. // These steps cannot be implemented using a for-of loop. // See <https://bugs.ecmascript.org/show_bug.cgi?id=2883>. while (true) { - // Steps 6.g.i-iii. + // Step 5.e.i. + // Disabled for performance reason. We won't hit this case on + // normal array, since _DefineDataProperty will throw before it. + // We could hit this when |A| is a proxy and it ignores + // |_DefineDataProperty|, but it happens only after too long loop. + /* + if (k >= 0x1fffffffffffff) { + IteratorCloseThrow(iterator); + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + } + */ + + // Step 5.e.iii. var next = callContentFunction(iterator.next, iterator); if (!IsObject(next)) ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE); - // Step 6.g.iv. + // Step 5.e.iv. if (next.done) { A.length = k; return A; } - // Steps 6.g.v-vi. + // Steps 5.e.v. var nextValue = next.value; - // Steps 6.g.vii-viii. - var mappedValue = mapping ? callContentFunction(mapfn, thisArg, nextValue, k) : nextValue; + // Steps 5.e.vi-vii. + try { + var mappedValue = mapping ? callContentFunction(mapfn, thisArg, nextValue, k) : nextValue; - // Steps 6.g.ix-xi. - _DefineDataProperty(A, k++, mappedValue); + // Steps 5.e.ii (reordered), 5.e.viii. + _DefineDataProperty(A, k++, mappedValue); + } catch (e) { + // Steps 5.e.vi.2, 5.e.ix. + IteratorCloseThrow(iterator); + throw e; + } } } diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 432364614..27a12bfff 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -40,11 +40,18 @@ function MapConstructorInit(iterable) { var nextItem = next.value; // Step 8.d. - if (!IsObject(nextItem)) + if (!IsObject(nextItem)) { + IteratorCloseThrow(iter); ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Map"); + } // Steps 8.e-j. - callContentFunction(adder, map, nextItem[0], nextItem[1]); + try { + callContentFunction(adder, map, nextItem[0], nextItem[1]); + } catch (e) { + IteratorCloseThrow(iter); + throw e; + } } } diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 59c97e529..c781a336d 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -1369,7 +1369,8 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto / static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, HandleObject promiseObj, - HandleObject resolve, HandleObject reject); + HandleObject resolve, HandleObject reject, + bool* done); // ES2016, 25.4.4.1. static bool @@ -1410,12 +1411,14 @@ Promise_static_all(JSContext* cx, unsigned argc, Value* vp) // Step 6 (implicit). // Step 7. - bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject); + bool done; + bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done); // Step 8. if (!result) { // Step 8.a. - // TODO: implement iterator closing. + if (!done) + iter.closeThrow(); // Step 8.b. return AbruptRejectPromise(cx, args, resultPromise, reject); @@ -1598,8 +1601,11 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res // ES2016, 25.4.4.1.1. static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, - HandleObject promiseObj, HandleObject resolve, HandleObject reject) + HandleObject promiseObj, HandleObject resolve, HandleObject reject, + bool* done) { + *done = false; + RootedObject unwrappedPromiseObj(cx); if (IsWrapper(promiseObj)) { unwrappedPromiseObj = CheckedUnwrap(promiseObj); @@ -1666,14 +1672,19 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, RootedValue rejectFunVal(cx, ObjectOrNullValue(reject)); while (true) { - bool done; - // Steps a, b, c, e, f, g. - if (!iterator.next(&nextValue, &done)) + // Steps a-c, e-g. + if (!iterator.next(&nextValue, done)) { + // Steps b, f. + *done = true; + + // Steps c, g. return false; + } // Step d. - if (done) { + if (*done) { // Step d.i (implicit). + // Step d.ii. int32_t remainingCount = dataHolder->decreaseRemainingCount(); @@ -1822,7 +1833,8 @@ PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp) static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, HandleObject promiseObj, - HandleObject resolve, HandleObject reject); + HandleObject resolve, HandleObject reject, + bool* done); // ES2016, 25.4.4.3. static bool @@ -1863,12 +1875,14 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp) // Step 6 (implicit). // Step 7. - bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject); + bool done; + bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done); // Step 8. if (!result) { // Step 8.a. - // TODO: implement iterator closing. + if (!done) + iter.closeThrow(); // Step 8.b. return AbruptRejectPromise(cx, args, resultPromise, reject); @@ -1882,25 +1896,30 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp) // ES2016, 25.4.4.3.1. static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, - HandleObject promiseObj, HandleObject resolve, HandleObject reject) + HandleObject promiseObj, HandleObject resolve, HandleObject reject, + bool* done) { + *done = false; MOZ_ASSERT(C->isConstructor()); RootedValue CVal(cx, ObjectValue(*C)); RootedValue nextValue(cx); RootedValue resolveFunVal(cx, ObjectOrNullValue(resolve)); RootedValue rejectFunVal(cx, ObjectOrNullValue(reject)); - bool done; while (true) { // Steps a-c, e-g. - if (!iterator.next(&nextValue, &done)) + if (!iterator.next(&nextValue, done)) { + // Steps b, f. + *done = true; + + // Steps c, g. return false; + } // Step d. - if (done) { - // Step d.i. - // TODO: implement iterator closing. + if (*done) { + // Step d.i (implicit). // Step d.ii. return true; diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index accc70120..c61a49ef8 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -40,7 +40,12 @@ function SetConstructorInit(iterable) { var nextValue = next.value; // Steps 8.d-e. - callContentFunction(adder, set, nextValue); + try { + callContentFunction(adder, set, nextValue); + } catch (e) { + IteratorCloseThrow(iter); + throw e; + } } } diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index bfb1fe7f4..2dece3801 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -154,6 +154,29 @@ function GetIterator(obj, method) { return iterator; } +// ES2017 draft rev 7.4.6. +// When completion.[[Type]] is throw. +function IteratorCloseThrow(iter) { + // Steps 1-2 (implicit) + + // Step 3. + var returnMethod = GetMethod(iter, "return"); + + // Step 4 (done in caller). + if (returnMethod === undefined) + return; + + try { + // Step 5. + callContentFunction(returnMethod, iter); + } catch (e) { + } + + // Step 6 (done in caller). + + // Steps 7-9 (skipped). +} + var _builtinCtorsCache = {__proto__: null}; function GetBuiltinConstructor(builtinName) { diff --git a/js/src/builtin/WeakMap.js b/js/src/builtin/WeakMap.js index 066a72bfe..708be8424 100644 --- a/js/src/builtin/WeakMap.js +++ b/js/src/builtin/WeakMap.js @@ -40,10 +40,17 @@ function WeakMapConstructorInit(iterable) { var nextItem = next.value; // Step 8.d. - if (!IsObject(nextItem)) + if (!IsObject(nextItem)) { + IteratorCloseThrow(iter); ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "WeakMap"); + } // Steps 8.e-j. - callContentFunction(adder, map, nextItem[0], nextItem[1]); + try { + callContentFunction(adder, map, nextItem[0], nextItem[1]); + } catch (e) { + IteratorCloseThrow(iter); + throw e; + } } } diff --git a/js/src/builtin/WeakSet.js b/js/src/builtin/WeakSet.js index eb7c2378f..8589f9dc6 100644 --- a/js/src/builtin/WeakSet.js +++ b/js/src/builtin/WeakSet.js @@ -40,7 +40,12 @@ function WeakSetConstructorInit(iterable) { var nextValue = next.value; // Steps 8.d-e. - callContentFunction(adder, set, nextValue); + try { + callContentFunction(adder, set, nextValue); + } catch (e) { + IteratorCloseThrow(iter); + throw e; + } } } |