static NativeGenerator init(ScriptableObject scope, boolean sealed) {
    // Generator
    // Can't use "NativeGenerator().exportAsJSClass" since we don't want
    // to define "Generator" as a constructor in the top-level scope.

    NativeGenerator prototype = new NativeGenerator();
    if (scope != null) {
      prototype.setParentScope(scope);
      prototype.setPrototype(getObjectPrototype(scope));
    }
    prototype.activatePrototypeMap(MAX_PROTOTYPE_ID);
    if (sealed) {
      prototype.sealObject();
    }

    // Need to access Generator prototype when constructing
    // Generator instances, but don't have a generator constructor
    // to use to find the prototype. Use the "associateValue"
    // approach instead.
    if (scope != null) {
      scope.associateValue(GENERATOR_TAG, prototype);
    }

    return prototype;
  }
  static void init(ScriptableObject scope, boolean sealed) {
    // Iterator
    NativeIterator iterator = new NativeIterator();
    iterator.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);

    // Generator
    NativeGenerator.init(scope, sealed);

    // StopIteration
    NativeObject obj = new StopIteration();
    obj.setPrototype(getObjectPrototype(scope));
    obj.setParentScope(scope);
    if (sealed) {
      obj.sealObject();
    }
    ScriptableObject.defineProperty(scope, STOP_ITERATION, obj, ScriptableObject.DONTENUM);
    // Use "associateValue" so that generators can continue to
    // throw StopIteration even if the property of the global
    // scope is replaced or deleted.
    scope.associateValue(ITERATOR_TAG, obj);
  }
  @Override
  public Object execIdCall(
      IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
    if (!f.hasTag(GENERATOR_TAG)) {
      return super.execIdCall(f, cx, scope, thisObj, args);
    }
    int id = f.methodId();

    if (!(thisObj instanceof NativeGenerator)) throw incompatibleCallError(f);

    NativeGenerator generator = (NativeGenerator) thisObj;

    switch (id) {
      case Id_close:
        // need to run any pending finally clauses
        return generator.resume(cx, scope, GENERATOR_CLOSE, new GeneratorClosedException());

      case Id_next:
        // arguments to next() are ignored
        generator.firstTime = false;
        return generator.resume(cx, scope, GENERATOR_SEND, Undefined.instance);

      case Id_send:
        {
          Object arg = args.length > 0 ? args[0] : Undefined.instance;
          if (generator.firstTime && !arg.equals(Undefined.instance)) {
            throw ScriptRuntime.typeError0("msg.send.newborn");
          }
          return generator.resume(cx, scope, GENERATOR_SEND, arg);
        }

      case Id_throw:
        return generator.resume(
            cx, scope, GENERATOR_THROW, args.length > 0 ? args[0] : Undefined.instance);

      case Id___iterator__:
        return thisObj;

      default:
        throw new IllegalArgumentException(String.valueOf(id));
    }
  }