diff options
Diffstat (limited to 'js/src/builtin/Generator.js')
-rw-r--r-- | js/src/builtin/Generator.js | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/js/src/builtin/Generator.js b/js/src/builtin/Generator.js new file mode 100644 index 000000000..bd1549660 --- /dev/null +++ b/js/src/builtin/Generator.js @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function StarGeneratorNext(val) { + // The IsSuspendedStarGenerator call below is not necessary for + // correctness. It's a performance optimization to check for the + // common case with a single call. It's also inlined in Baseline. + + if (!IsSuspendedStarGenerator(this)) { + if (!IsObject(this) || !IsStarGeneratorObject(this)) + return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorNext"); + + if (StarGeneratorObjectIsClosed(this)) + return { value: undefined, done: true }; + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + } + + try { + return resumeGenerator(this, val, 'next'); + } catch (e) { + if (!StarGeneratorObjectIsClosed(this)) + GeneratorSetClosed(this); + throw e; + } +} + +function StarGeneratorThrow(val) { + if (!IsSuspendedStarGenerator(this)) { + if (!IsObject(this) || !IsStarGeneratorObject(this)) + return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorThrow"); + + if (StarGeneratorObjectIsClosed(this)) + throw val; + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + } + + try { + return resumeGenerator(this, val, 'throw'); + } catch (e) { + if (!StarGeneratorObjectIsClosed(this)) + GeneratorSetClosed(this); + throw e; + } +} + +function StarGeneratorReturn(val) { + if (!IsSuspendedStarGenerator(this)) { + if (!IsObject(this) || !IsStarGeneratorObject(this)) + return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorReturn"); + + if (StarGeneratorObjectIsClosed(this)) + return { value: val, done: true }; + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + } + + try { + var rval = { value: val, done: true }; + return resumeGenerator(this, rval, 'close'); + } catch (e) { + if (!StarGeneratorObjectIsClosed(this)) + GeneratorSetClosed(this); + throw e; + } +} + +function LegacyGeneratorNext(val) { + if (!IsObject(this) || !IsLegacyGeneratorObject(this)) + return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorNext"); + + if (LegacyGeneratorObjectIsClosed(this)) + ThrowStopIteration(); + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + + try { + return resumeGenerator(this, val, 'next'); + } catch(e) { + if (!LegacyGeneratorObjectIsClosed(this)) + GeneratorSetClosed(this); + throw e; + } +} +_SetCanonicalName(LegacyGeneratorNext, "next"); + +function LegacyGeneratorThrow(val) { + if (!IsObject(this) || !IsLegacyGeneratorObject(this)) + return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorThrow"); + + if (LegacyGeneratorObjectIsClosed(this)) + throw val; + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + + try { + return resumeGenerator(this, val, 'throw'); + } catch(e) { + if (!LegacyGeneratorObjectIsClosed(this)) + GeneratorSetClosed(this); + throw e; + } +} + +// Called by js::CloseIterator. +function LegacyGeneratorCloseInternal() { + assert(IsObject(this), "Not an object: " + ToString(this)); + assert(IsLegacyGeneratorObject(this), "Not a legacy generator object: " + ToString(this)); + assert(!LegacyGeneratorObjectIsClosed(this), "Already closed: " + ToString(this)); + + if (GeneratorIsRunning(this)) + ThrowTypeError(JSMSG_NESTING_GENERATOR); + + resumeGenerator(this, undefined, 'close'); + if (!LegacyGeneratorObjectIsClosed(this)) + CloseClosingLegacyGeneratorObject(this); +} + +function LegacyGeneratorClose() { + if (!IsObject(this) || !IsLegacyGeneratorObject(this)) + return callFunction(CallLegacyGeneratorMethodIfWrapped, this, "LegacyGeneratorClose"); + + if (LegacyGeneratorObjectIsClosed(this)) + return; + + callFunction(LegacyGeneratorCloseInternal, this); +} + +function InterpretGeneratorResume(gen, val, kind) { + // If we want to resume a generator in the interpreter, the script containing + // the resumeGenerator/JSOP_RESUME also has to run in the interpreter. The + // forceInterpreter() call below compiles to a bytecode op that prevents us + // from JITing this script. + forceInterpreter(); + if (kind === "next") + return resumeGenerator(gen, val, "next"); + if (kind === "throw") + return resumeGenerator(gen, val, "throw"); + assert(kind === "close", "Invalid resume kind"); + return resumeGenerator(gen, val, "close"); +} |