summaryrefslogtreecommitdiffstats
path: root/js/src/jsiter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsiter.cpp')
-rw-r--r--js/src/jsiter.cpp52
1 files changed, 52 insertions, 0 deletions
diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp
index 63c81e6af..c1ae5dc15 100644
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -12,6 +12,7 @@
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
+#include "mozilla/Unused.h"
#include "jsarray.h"
#include "jsatom.h"
@@ -1229,6 +1230,7 @@ js::CloseIterator(JSContext* cx, HandleObject obj)
}
return LegacyGeneratorObject::close(cx, obj);
}
+
return true;
}
@@ -1246,6 +1248,56 @@ js::UnwindIteratorForException(JSContext* cx, HandleObject obj)
return true;
}
+bool
+js::IteratorCloseForException(JSContext* cx, HandleObject obj)
+{
+ MOZ_ASSERT(cx->isExceptionPending());
+
+ bool isClosingGenerator = cx->isClosingGenerator();
+ JS::AutoSaveExceptionState savedExc(cx);
+
+ // Implements IteratorClose (ES 7.4.6) for exception unwinding. See
+ // also the bytecode generated by BytecodeEmitter::emitIteratorClose.
+
+ // Step 3.
+ //
+ // Get the "return" method.
+ RootedValue returnMethod(cx);
+ if (!GetProperty(cx, obj, obj, cx->names().return_, &returnMethod))
+ return false;
+
+ // Step 4.
+ //
+ // Do nothing if "return" is null or undefined. Throw a TypeError if the
+ // method is not IsCallable.
+ if (returnMethod.isNullOrUndefined())
+ return true;
+ if (!IsCallable(returnMethod))
+ return ReportIsNotFunction(cx, returnMethod);
+
+ // Step 5, 6, 8.
+ //
+ // Call "return" if it is not null or undefined.
+ RootedValue rval(cx);
+ bool ok = Call(cx, returnMethod, obj, &rval);
+ if (isClosingGenerator) {
+ // Closing an iterator is implemented as an exception, but in spec
+ // terms it is a Completion value with [[Type]] return. In this case
+ // we *do* care if the call threw and if it returned an object.
+ if (!ok)
+ return false;
+ if (!rval.isObject())
+ return ThrowCheckIsObject(cx, CheckIsObjectKind::IteratorReturn);
+ } else {
+ // We don't care if the call threw or that it returned an Object, as
+ // Step 6 says if IteratorClose is being called during a throw, the
+ // original throw has primacy.
+ savedExc.restore();
+ }
+
+ return true;
+}
+
void
js::UnwindIteratorForUncatchableException(JSContext* cx, JSObject* obj)
{