Chromium Code Reviews| Index: src/js/generator.js |
| diff --git a/src/js/generator.js b/src/js/generator.js |
| index 7f43656ebcf5c1fb4cfb5eca311e8381082f5c33..c88b15d2b46bb8a5a9d05679638b305def175a70 100644 |
| --- a/src/js/generator.js |
| +++ b/src/js/generator.js |
| @@ -26,6 +26,23 @@ utils.Import(function(from) { |
| // Generator functions and objects are specified by ES6, sections 15.19.3 and |
| // 15.19.4. |
| +// Explanation of the use of %GeneratorClose: |
| +// |
| +// There are two situations in which resuming a generator must result in |
| +// closing it (in ES6 terms: setting [[GeneratorState]] to "completed"). |
| +// - When the generator throws. We close it by calling %GeneratorClose in the |
| +// catch blocks below. |
| +// - When the generator returns a "done" iterator result. |
| +// * For GeneratorObjectNext and GeneratorObjectThrow this can only happen |
| +// when the generator hits a "final" yield (as introduced by the |
| +// parser). A final yield already takes care of closing the generator |
| +// itself, so we don't need to do it here. |
| +// * For GeneratorObjectReturn this can also happen if the triggered return is |
| +// not "caught" and terminates the generator. We handle this here by just |
| +// always calling %GeneratorClose when the received result is "done". This |
| +// may include cases where the generator has already been closed but doing |
| +// it twice is harmless. |
| + |
| function GeneratorObjectNext(value) { |
| if (!IS_GENERATOR(this)) { |
| throw MakeTypeError(kIncompatibleMethodReceiver, |
| @@ -44,7 +61,35 @@ function GeneratorObjectNext(value) { |
| } |
| } else if (continuation == 0) { |
| // Generator is already closed. |
| - return { value: void 0, done: true }; |
| + return { value: UNDEFINED, done: true }; |
|
Dan Ehrenberg
2016/01/20 23:48:21
Not that this should be done in this patch, but sh
Benedikt Meurer
2016/01/21 05:09:02
Nice catch! Yes that should use %_CreateIterResult
|
| + } else { |
| + // Generator is running. |
| + throw MakeTypeError(kGeneratorRunning); |
| + } |
| +} |
| + |
| + |
| +function GeneratorObjectReturn(value) { |
| + if (!IS_GENERATOR(this)) { |
| + throw MakeTypeError(kIncompatibleMethodReceiver, |
| + '[Generator].prototype.return', this); |
| + } |
| + |
| + var continuation = %GeneratorGetContinuation(this); |
| + if (continuation > 0) { |
| + // Generator is suspended. |
| + DEBUG_PREPARE_STEP_IN_IF_STEPPING(this); |
| + try { |
| + let result = %_GeneratorReturn(this, value); |
| + if (result.done) %GeneratorClose(this); |
| + return result; |
| + } catch (e) { |
| + %GeneratorClose(this); |
| + throw e; |
| + } |
| + } else if (continuation == 0) { |
| + // Generator is already closed. |
| + return { value: value, done: true }; |
|
Benedikt Meurer
2016/01/21 05:09:02
Use %_CreateIterResultObject, as explained above.
|
| } else { |
| // Generator is running. |
| throw MakeTypeError(kGeneratorRunning); |
| @@ -78,9 +123,11 @@ function GeneratorObjectThrow(exn) { |
| // ---------------------------------------------------------------------------- |
| -// Both Runtime_GeneratorNext and Runtime_GeneratorThrow are supported by |
| -// neither Crankshaft nor TurboFan, disable optimization of wrappers here. |
| +// None of the three resume operations (Runtime_GeneratorNext, |
| +// Runtime_GeneratorReturn, Runtime_GeneratorThrow) is supported by |
| +// Crankshaft or TurboFan. Disable optimization of wrappers here. |
| %NeverOptimizeFunction(GeneratorObjectNext); |
| +%NeverOptimizeFunction(GeneratorObjectReturn); |
| %NeverOptimizeFunction(GeneratorObjectThrow); |
| // Set up non-enumerable functions on the generator prototype object. |
| @@ -88,6 +135,7 @@ var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype; |
| utils.InstallFunctions(GeneratorObjectPrototype, |
| DONT_ENUM, |
| ["next", GeneratorObjectNext, |
| + "return", GeneratorObjectReturn, |
| "throw", GeneratorObjectThrow]); |
| %AddNamedProperty(GeneratorObjectPrototype, "constructor", |