diff --git a/mozilla/js/rhino/build.properties b/mozilla/js/rhino/build.properties
index 6cb2b109d41..8f5149e3cca 100644
--- a/mozilla/js/rhino/build.properties
+++ b/mozilla/js/rhino/build.properties
@@ -36,9 +36,9 @@
name: rhino
Name: Rhino
-version: 1_6R6pre
+version: 1_7R1pre
# See Context#getImplementationVersion() for format of this!
-implementation.version: Rhino 1.6 release 6 Pre ${implementation.date}
+implementation.version: Rhino 1.7 release 1 Pre ${implementation.date}
build.dir: build
rhino.jar: js.jar
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Context.java b/mozilla/js/rhino/src/org/mozilla/javascript/Context.java
index 13f340991b7..d5e5fc5b2b2 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Context.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Context.java
@@ -133,6 +133,11 @@ public class Context
*/
public static final int VERSION_1_6 = 160;
+ /**
+ * JavaScript 1.7
+ */
+ public static final int VERSION_1_7 = 170;
+
/**
* Controls behaviour of Date.prototype.getYear().
* If hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,
@@ -758,6 +763,7 @@ public class Context
case VERSION_1_4:
case VERSION_1_5:
case VERSION_1_6:
+ case VERSION_1_7:
return true;
}
return false;
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Decompiler.java b/mozilla/js/rhino/src/org/mozilla/javascript/Decompiler.java
index d4198feecf0..d57440e14a3 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Decompiler.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Decompiler.java
@@ -747,6 +747,10 @@ public class Decompiler
case Token.CONST:
result.append("const ");
break;
+
+ case Token.YIELD:
+ result.append("yield ");
+ break;
case Token.NOT:
result.append('!');
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/FunctionNode.java b/mozilla/js/rhino/src/org/mozilla/javascript/FunctionNode.java
index 3c7ba325e8a..b427ebf7205 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/FunctionNode.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/FunctionNode.java
@@ -57,6 +57,10 @@ public class FunctionNode extends ScriptOrFnNode {
public boolean getIgnoreDynamicScope() {
return itsIgnoreDynamicScope;
}
+
+ public boolean isGenerator() {
+ return itsIsGenerator;
+ }
/**
* There are three types of functions that can be defined. The first
@@ -82,7 +86,8 @@ public class FunctionNode extends ScriptOrFnNode {
}
String functionName;
- boolean itsNeedsActivation;
int itsFunctionType;
+ boolean itsNeedsActivation;
boolean itsIgnoreDynamicScope;
+ boolean itsIsGenerator;
}
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java b/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java
index 5db480dc5ec..0bcc9e5824d 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java
@@ -950,6 +950,19 @@ final class IRFactory
return new Node(nodeType, child);
}
+ Node createYield(Node child, int lineno)
+ {
+ if (!parser.insideFunction()) {
+ parser.reportError("msg.bad.yield");
+ }
+ setRequiresActivation();
+ setIsGenerator();
+ if (child != null)
+ return new Node(Token.YIELD, child, lineno);
+ else
+ return new Node(Token.YIELD, lineno);
+ }
+
Node createCallOrNew(int nodeType, Node child)
{
int type = Node.NON_SPECIALCALL;
@@ -1417,6 +1430,13 @@ final class IRFactory
}
}
+ private void setIsGenerator()
+ {
+ if (parser.insideFunction()) {
+ ((FunctionNode)parser.currentScriptOrFn).itsIsGenerator = true;
+ }
+ }
+
private Parser parser;
private static final int LOOP_DO_WHILE = 0;
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/InterpretedFunction.java b/mozilla/js/rhino/src/org/mozilla/javascript/InterpretedFunction.java
index ee9dbcc3349..bbb32928365 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/InterpretedFunction.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/InterpretedFunction.java
@@ -187,6 +187,12 @@ final class InterpretedFunction extends NativeFunction implements Script
return idata;
}
+ Object resumeGenerator(Context cx, Scriptable scope, int operation,
+ Object state, Object value)
+ {
+ return Interpreter.resumeGenerator(cx, scope, operation, state, value);
+ }
+
protected int getLanguageVersion()
{
return idata.languageVersion;
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java b/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java
index 5c45cd432ec..5b562e0a8dd 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java
@@ -160,20 +160,24 @@ public class Interpreter
Icode_TAIL_CALL = -55,
- // Clear local to allow GC its context
+ // Clear local to allow GC its context
Icode_LOCAL_CLEAR = -56,
- // Literal get/set
+ // Literal get/set
Icode_LITERAL_GETTER = -57,
Icode_LITERAL_SETTER = -58,
- // const
+ // const
Icode_SETCONST = -59,
Icode_SETCONSTVAR = -60,
Icode_SETCONSTVAR1 = -61,
+ // Generator opcodes (along with Token.YIELD)
+ Icode_GENERATOR = -62,
+ Icode_GENERATOR_END = -63,
+
// Last icode
- MIN_ICODE = -61;
+ MIN_ICODE = -63;
// data for parsing
@@ -335,7 +339,18 @@ public class Interpreter
Kit.codeBug();
}
}
+ }
+ private static CallFrame captureFrameForGenerator(CallFrame frame) {
+ frame.frozen = true;
+ CallFrame result = frame.cloneFrozen();
+ frame.frozen = false;
+
+ // now isolate this frame from its previous context
+ result.parentFrame = null;
+ result.frameIndex = 0;
+
+ return result;
}
static {
@@ -429,6 +444,8 @@ public class Interpreter
case Icode_SETCONST: return "SETCONST";
case Icode_SETCONSTVAR: return "SETCONSTVAR";
case Icode_SETCONSTVAR1: return "SETCONSTVAR1";
+ case Icode_GENERATOR: return "GENERATOR";
+ case Icode_GENERATOR_END: return "GENERATOR_END";
}
// icode without name
@@ -517,6 +534,10 @@ public class Interpreter
itsData.useDynamicScope = true;
}
}
+ if (theFunction.isGenerator()) {
+ addIcode(Icode_GENERATOR);
+ addUint16(theFunction.getBaseLineno() & 0xFFFF);
+ }
generateICodeFromTree(theFunction.getLastChild());
}
@@ -863,7 +884,11 @@ public class Interpreter
case Token.RETURN:
updateLineNumber(node);
- if (child != null) {
+ if (node.getIntProp(Node.GENERATOR_END_PROP, 0) != 0) {
+ // We're in a generator, so change RETURN to GENERATOR_END
+ addIcode(Icode_GENERATOR_END);
+ addUint16(itsLineNumber & 0xFFFF);
+ } else if (child != null) {
visitExpression(child, ECF_TAIL);
addToken(Token.RETURN);
stackChange(-1);
@@ -884,6 +909,9 @@ public class Interpreter
stackChange(-1);
break;
+ case Icode_GENERATOR:
+ break;
+
default:
throw badTree(node);
}
@@ -1322,6 +1350,17 @@ public class Interpreter
addToken(type);
break;
+ case Token.YIELD:
+ if (child != null) {
+ visitExpression(child, 0);
+ } else {
+ addIcode(Icode_UNDEF);
+ stackChange(1);
+ }
+ addToken(Token.YIELD);
+ addUint16(node.getLineno() & 0xFFFF);
+ break;
+
default:
throw badTree(node);
}
@@ -1605,7 +1644,7 @@ public class Interpreter
byte[] array = itsData.itsICode;
int top = itsICodeTop;
if (top == array.length) {
- array = increaseICodeCapasity(1);
+ array = increaseICodeCapacity(1);
}
array[top] = (byte)value;
itsICodeTop = top + 1;
@@ -1617,7 +1656,7 @@ public class Interpreter
byte[] array = itsData.itsICode;
int top = itsICodeTop;
if (top + 2 > array.length) {
- array = increaseICodeCapasity(2);
+ array = increaseICodeCapacity(2);
}
array[top] = (byte)(value >>> 8);
array[top + 1] = (byte)value;
@@ -1629,7 +1668,7 @@ public class Interpreter
byte[] array = itsData.itsICode;
int top = itsICodeTop;
if (top + 4 > array.length) {
- array = increaseICodeCapasity(4);
+ array = increaseICodeCapacity(4);
}
array[top] = (byte)(i >>> 24);
array[top + 1] = (byte)(i >>> 16);
@@ -1658,7 +1697,7 @@ public class Interpreter
byte[] array = itsData.itsICode;
int top = itsICodeTop;
if (top + 3 > array.length) {
- array = increaseICodeCapasity(3);
+ array = increaseICodeCapacity(3);
}
array[top] = (byte)gotoOp;
// Offset would written later
@@ -1774,7 +1813,7 @@ public class Interpreter
itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE;
}
- private byte[] increaseICodeCapasity(int extraSize)
+ private byte[] increaseICodeCapacity(int extraSize)
{
int capacity = itsData.itsICode.length;
int top = itsICodeTop;
@@ -1958,7 +1997,11 @@ public class Interpreter
case Token.NEW :
out.println(tname+' '+indexReg);
break;
- case Token.THROW : {
+ case Token.THROW :
+ case Token.YIELD :
+ case Icode_GENERATOR :
+ case Icode_GENERATOR_END :
+ {
int line = getIndex(iCode, pc);
out.println(tname + " : " + line);
pc += 2;
@@ -2006,6 +2049,24 @@ public class Interpreter
pc += 4;
break;
}
+ case Icode_REG_IND_C0:
+ indexReg = 0;
+ break;
+ case Icode_REG_IND_C1:
+ indexReg = 1;
+ break;
+ case Icode_REG_IND_C2:
+ indexReg = 2;
+ break;
+ case Icode_REG_IND_C3:
+ indexReg = 3;
+ break;
+ case Icode_REG_IND_C4:
+ indexReg = 4;
+ break;
+ case Icode_REG_IND_C5:
+ indexReg = 5;
+ break;
case Icode_REG_IND1: {
indexReg = 0xFF & iCode[pc];
out.println(tname+" "+indexReg);
@@ -2062,6 +2123,9 @@ public class Interpreter
{
switch (bytecode) {
case Token.THROW :
+ case Token.YIELD:
+ case Icode_GENERATOR:
+ case Icode_GENERATOR_END:
// source line
return 1 + 2;
@@ -2326,6 +2390,40 @@ public class Interpreter
return interpretLoop(cx, frame, null);
}
+ static class GeneratorState {
+ GeneratorState(int operation, Object value) {
+ this.operation = operation;
+ this.value = value;
+ }
+ int operation;
+ Object value;
+ RuntimeException returnedException;
+ }
+
+ public static Object resumeGenerator(Context cx,
+ Scriptable scope,
+ int operation,
+ Object savedState,
+ Object value)
+ {
+ CallFrame frame = (CallFrame) savedState;
+ GeneratorState generatorState = new GeneratorState(operation, value);
+ if (operation == NativeGenerator.GENERATOR_CLOSE) {
+ try {
+ return interpretLoop(cx, frame, generatorState);
+ } catch (RuntimeException e) {
+ // Only propagate exceptions other than closingException
+ if (e != value)
+ throw e;
+ }
+ return Undefined.instance;
+ }
+ Object result = interpretLoop(cx, frame, generatorState);
+ if (generatorState.returnedException != null)
+ throw generatorState.returnedException;
+ return result;
+ }
+
public static Object restartContinuation(Continuation c, Context cx,
Scriptable scope, Object[] args)
{
@@ -2388,9 +2486,15 @@ public class Interpreter
// catch bugs with using indeReg to access array eleemnts before
// initializing indexReg.
+ GeneratorState generatorState = null;
if (throwable != null) {
- // Assert assumptions
- if (!(throwable instanceof ContinuationJump)) {
+ if (throwable instanceof GeneratorState) {
+ generatorState = (GeneratorState) throwable;
+
+ // reestablish this call frame
+ enterFrame(cx, frame, ScriptRuntime.emptyArgs, true);
+ throwable = null;
+ } else if (!(throwable instanceof ContinuationJump)) {
// It should be continuation
Kit.codeBug();
}
@@ -2493,7 +2597,7 @@ public class Interpreter
}
} else {
- if (frame.frozen) Kit.codeBug();
+ if (generatorState == null && frame.frozen) Kit.codeBug();
}
// Use local variables for constant values in frame
@@ -2508,7 +2612,7 @@ public class Interpreter
// Use local for stackTop as well. Since execption handlers
// can only exist at statement level where stack is empty,
- // it is necessary to save/restore stackTop only accross
+ // it is necessary to save/restore stackTop only across
// function calls and normal returns.
int stackTop = frame.savedStackTop;
@@ -2523,8 +2627,76 @@ public class Interpreter
int op = iCode[frame.pc++];
jumplessRun: {
- // Back indent to ease imlementation reading
+ // Back indent to ease implementation reading
switch (op) {
+ case Icode_GENERATOR: {
+ if (!frame.frozen) {
+ // First time encountering this opcode: create new generator
+ // object and return
+ frame.pc--; // we want to come back here when we resume
+ CallFrame generatorFrame = captureFrameForGenerator(frame);
+ generatorFrame.frozen = true;
+ NativeGenerator generator
+ = new NativeGenerator(generatorFrame.fnOrScript, generatorFrame);
+ ScriptRuntime.setObjectProtoAndParent(generator,
+ ScriptRuntime.getTopCallScope(cx));
+ frame.result = generator;
+ break Loop;
+ } else {
+ // We are now resuming execution. Fall through to YIELD case.
+ }
+ }
+ // fall through...
+ case Token.YIELD: {
+ if (!frame.frozen) {
+ if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
+ // Error: no yields when generator is closing
+ throw ScriptRuntime.typeError0("msg.yield.closing");
+ }
+ // return to our caller (which should be a method of NativeGenerator)
+ frame.frozen = true;
+ frame.result = stack[stackTop];
+ frame.resultDbl = sDbl[stackTop];
+ frame.savedStackTop = stackTop;
+ frame.pc--; // we want to come back here when we resume
+ ScriptRuntime.exitActivationFunction(cx);
+ return (frame.result != DBL_MRK)
+ ? frame.result
+ : ScriptRuntime.wrapNumber(frame.resultDbl);
+ } else {
+ // we are resuming execution
+ frame.frozen = false;
+ int sourceLine = getIndex(iCode, frame.pc);
+ frame.pc += 2; // skip line number data
+ if (generatorState.operation == NativeGenerator.GENERATOR_THROW) {
+ // processing a call to .throw(exception): must
+ // act as if exception was thrown from resumption point
+ throwable = new JavaScriptException(generatorState.value,
+ frame.idata.itsSourceFile,
+ sourceLine);
+ break withoutExceptions;
+ }
+ if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
+ throwable = generatorState.value;
+ break withoutExceptions;
+ }
+ if (generatorState.operation != NativeGenerator.GENERATOR_SEND)
+ throw Kit.codeBug();
+ if (op == Token.YIELD)
+ stack[stackTop] = generatorState.value;
+ continue Loop;
+ }
+ }
+ case Icode_GENERATOR_END: {
+ // throw StopIteration
+ frame.frozen = true;
+ Scriptable top = ScriptableObject.getTopLevelScope(frame.scope);
+ Object e = top.get(NativeGenerator.STOP_ITERATION, frame.scope);
+ int sourceLine = getIndex(iCode, frame.pc);
+ generatorState.returnedException =
+ new JavaScriptException(e, frame.idata.itsSourceFile, sourceLine);
+ break Loop;
+ }
case Token.THROW: {
Object value = stack[stackTop];
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
@@ -3124,7 +3296,8 @@ switch (op) {
// optimization will create a "hole" in the context stack.
// The correct thing to do may be to disable tail call
// optimization if the code is being debugged.
- exitFrame(cx, frame, null); }
+ exitFrame(cx, frame, null);
+ }
initFrame(cx, calleeScope, funThisObj, stack, sDbl,
stackTop + 2, indexReg, ifun, callParentFrame,
calleeFrame);
@@ -3704,7 +3877,12 @@ switch (op) {
int exState;
ContinuationJump cjump = null;
- if (throwable instanceof JavaScriptException) {
+ if (generatorState != null &&
+ generatorState.operation == NativeGenerator.GENERATOR_CLOSE &&
+ throwable == generatorState.value)
+ {
+ exState = EX_FINALLY_STATE;
+ } else if (throwable instanceof JavaScriptException) {
exState = EX_CATCH_STATE;
} else if (throwable instanceof EcmaError) {
// an offical ECMA error object,
@@ -3762,7 +3940,7 @@ switch (op) {
continue StateLoop;
}
}
- // No allowed execption handlers in this frame, unwind
+ // No allowed exception handlers in this frame, unwind
// to parent and try to look there
exitFrame(cx, frame, throwable);
@@ -3988,7 +4166,8 @@ switch (op) {
return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
}
- private static void enterFrame(Context cx, CallFrame frame, Object[] args, boolean continuationRestart)
+ private static void enterFrame(Context cx, CallFrame frame, Object[] args,
+ boolean continuationRestart)
{
boolean usesActivation = frame.idata.itsNeedsActivation;
boolean isDebugged = frame.debuggerFrame != null;
@@ -3996,7 +4175,7 @@ switch (op) {
Scriptable scope = frame.scope;
if(scope == null) {
Kit.codeBug();
- } else if(continuationRestart) {
+ } else if (continuationRestart) {
// Walk the parent chain of frame.scope until a NativeCall is
// found. Normally, frame.scope is a NativeCall when called
// from initFrame() for a debugged or activatable function.
@@ -4010,7 +4189,9 @@ switch (op) {
break;
} else {
scope = scope.getParentScope();
- if(scope == null || (frame.parentFrame != null && frame.parentFrame.scope == scope)) {
+ if (scope == null || (frame.parentFrame != null &&
+ frame.parentFrame.scope == scope))
+ {
// If we get here, we didn't find a NativeCall in
// the call chain before reaching parent frame's
// scope. This should not be possible.
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeFunction.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeFunction.java
index 1392a3d954f..f4fb9e3a466 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeFunction.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeFunction.java
@@ -116,6 +116,16 @@ public abstract class NativeFunction extends BaseFunction
return null;
}
+ /*
+ * Resumes execution of a JS 1.7 generator.
+ */
+ /*abstract*/ Object resumeGenerator(Context cx, Scriptable scope,
+ int operation, Object state, Object value)
+ {
+ // TODO(js1.7gen): make abstract once bytecode generation is done
+ throw new EvaluatorException("Not yet implemented");
+ }
+
protected abstract int getLanguageVersion();
/**
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeGenerator.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeGenerator.java
new file mode 100755
index 00000000000..6325b9411be
--- /dev/null
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeGenerator.java
@@ -0,0 +1,227 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Norris Boyd
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript;
+
+/**
+ * This class implements generator objects. See
+ * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Generators
+ *
+ * @author Norris Boyd
+ */
+public final class NativeGenerator extends IdScriptableObject {
+ private static final Object GENERATOR_TAG = new Object();
+
+ static void init(Scriptable scope, boolean sealed) {
+ // Generator
+ new NativeGenerator().exportAsJSClass(MAX_PROTOTYPE_ID, 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);
+ }
+
+ /**
+ * Only for constructing the prototype object.
+ */
+ private NativeGenerator() { }
+
+ NativeGenerator(NativeFunction function, Object savedState) {
+ this.function = function;
+ this.savedState = savedState;
+ }
+
+ public static final String STOP_ITERATION = "StopIteration";
+
+ static class StopIteration extends NativeObject {
+ public String getClassName() { return STOP_ITERATION; }
+ }
+
+ public static final int GENERATOR_SEND = 0,
+ GENERATOR_THROW = 1,
+ GENERATOR_CLOSE = 2;
+
+ public String getClassName() {
+ return "Generator";
+ }
+
+ protected void initPrototypeId(int id) {
+ String s;
+ int arity;
+ switch (id) {
+ case Id_constructor: arity=1; s="constructor"; break;
+ case Id_close: arity=1; s="close"; break;
+ case Id_next: arity=1; s="next"; break;
+ case Id_send: arity=0; s="send"; break;
+ case Id_throw: arity=0; s="throw"; break;
+ default: throw new IllegalArgumentException(String.valueOf(id));
+ }
+ initPrototypeMethod(GENERATOR_TAG, id, s, arity);
+ }
+
+ 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_constructor:
+ // TODO(js1.7gen): Shouldn't have a constructor. Currently need
+ // one to get Generator.prototype
+ return null;
+
+ case Id_close:
+ // need to run any pending finally clauses
+ return generator.resume(cx, scope, GENERATOR_CLOSE,
+ new RuntimeException());
+
+ case Id_next:
+ // arguments to next() are ignored
+ generator.firstTime = false;
+ return generator.resume(cx, scope, GENERATOR_SEND,
+ Undefined.instance);
+
+ case Id_send:
+ if (generator.firstTime) {
+ throw ScriptRuntime.typeError0("msg.send.newborn");
+ }
+ return generator.resume(cx, scope, GENERATOR_SEND,
+ args.length > 0 ? args[0] : Undefined.instance);
+
+ case Id_throw:
+ return generator.resume(cx, scope, GENERATOR_THROW,
+ args.length > 0 ? args[0] : Undefined.instance);
+
+ default:
+ throw new IllegalArgumentException(String.valueOf(id));
+ }
+ }
+
+ private Object resume(Context cx, Scriptable scope, int operation,
+ Object value)
+ {
+ if (savedState == null) {
+ if (operation == GENERATOR_CLOSE)
+ return Undefined.instance;
+ Object thrown = operation == GENERATOR_THROW
+ ? value
+ : ScriptableObject.getTopLevelScope(scope).get(STOP_ITERATION,
+ scope);
+ throw new JavaScriptException(thrown, lineSource, lineNumber);
+ }
+ try {
+ synchronized (this) {
+ // generator execution is necessarily single-threaded and
+ // non-reentrant.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=349263
+ if (locked)
+ throw ScriptRuntime.typeError0("msg.already.exec.gen");
+ locked = true;
+ }
+ return function.resumeGenerator(cx, scope, operation, savedState,
+ value);
+ } catch (RhinoException e) {
+ lineNumber = e.lineNumber();
+ lineSource = e.lineSource();
+ savedState = null;
+ throw e;
+ } finally {
+ synchronized (this) {
+ locked = false;
+ }
+ if (operation == GENERATOR_CLOSE)
+ savedState = null;
+ }
+ }
+
+// #string_id_map#
+
+ protected int findPrototypeId(String s) {
+ int id;
+// #generated# Last update: 2007-05-09 08:23:27 EDT
+ L0: { id = 0; String X = null; int c;
+ int s_length = s.length();
+ if (s_length==4) {
+ c=s.charAt(0);
+ if (c=='n') { X="next";id=Id_next; }
+ else if (c=='s') { X="send";id=Id_send; }
+ }
+ else if (s_length==5) {
+ c=s.charAt(0);
+ if (c=='c') { X="close";id=Id_close; }
+ else if (c=='t') { X="throw";id=Id_throw; }
+ }
+ else if (s_length==11) { X="constructor";id=Id_constructor; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+ return id;
+ }
+
+ private static final int
+ Id_constructor = 1,
+ Id_close = 2,
+ Id_next = 3,
+ Id_send = 4,
+ Id_throw = 5,
+ MAX_PROTOTYPE_ID = 5;
+
+// #/string_id_map#
+
+ private NativeFunction function;
+ private Object savedState;
+ private String lineSource;
+ private int lineNumber;
+ private boolean firstTime = true;
+ private boolean locked;
+}
+
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Node.java b/mozilla/js/rhino/src/org/mozilla/javascript/Node.java
index 6dedac3d1a9..b4bcdd9510f 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Node.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Node.java
@@ -82,7 +82,8 @@ public class Node
NAME_PROP = 17, // property name
CONTROL_BLOCK_PROP = 18, // flags a control block that can drop off
PARENTHESIZED_PROP = 19, // expression is parenthesized
- LAST_PROP = 19;
+ GENERATOR_END_PROP = 20,
+ LAST_PROP = 20;
// values of ISNUMBER_PROP to specify
// which of the children are Number types
@@ -460,6 +461,7 @@ public class Node
case NAME_PROP: return "name_prop";
case CONTROL_BLOCK_PROP: return "control_block_prop";
case PARENTHESIZED_PROP: return "parenthesized_prop";
+ case GENERATOR_END_PROP: return "generator_end";
default: Kit.codeBug();
}
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java b/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java
index 53740a6434b..094dcac12f0 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java
@@ -135,6 +135,19 @@ public class NodeTransformer
case Token.RETURN:
{
+ boolean isGenerator = tree.getType() == Token.FUNCTION
+ && ((FunctionNode)tree).isGenerator();
+ if (isGenerator) {
+ node.putIntProp(Node.GENERATOR_END_PROP, 1);
+ /*
+ // Replace returns inside generators with throw STOP_ITERATION
+ node = replaceCurrent(parent, previous, node,
+ new Node(Token.THROW,
+ Node.newString(Token.NAME,
+ NativeGenerator.STOP_ITERATION),
+ node.getLineno()));
+ */
+ }
/* If we didn't support try/finally, it wouldn't be
* necessary to put LEAVEWITH nodes here... but as
* we do need a series of JSR FINALLY nodes before
@@ -169,7 +182,7 @@ public class NodeTransformer
Node returnNode = node;
Node returnExpr = returnNode.getFirstChild();
node = replaceCurrent(parent, previous, node, unwindBlock);
- if (returnExpr == null) {
+ if (returnExpr == null || isGenerator) {
unwindBlock.addChildToBack(returnNode);
} else {
Node store = new Node(Token.EXPR_RESULT, returnExpr);
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java b/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java
index 68029d42c1d..97d5c593cb2 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java
@@ -1069,44 +1069,9 @@ public class Parser
break;
}
- case Token.RETURN: {
- if (!insideFunction()) {
- reportError("msg.bad.return");
- }
- consumeToken();
- decompiler.addToken(Token.RETURN);
- int lineno = ts.getLineno();
-
- Node retExpr;
- /* This is ugly, but we don't want to require a semicolon. */
- tt = peekTokenOrEOL();
- switch (tt) {
- case Token.SEMI:
- case Token.RC:
- case Token.EOF:
- case Token.EOL:
- case Token.ERROR:
- retExpr = null;
- break;
- default:
- retExpr = expr(false);
- hasReturnValue = true;
- }
- pn = nf.createReturn(retExpr, lineno);
-
- // see if we need a strict mode warning
- if (retExpr == null) {
- if (functionEndFlags == Node.END_RETURNS_VALUE)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS;
- } else {
- if (functionEndFlags == Node.END_RETURNS)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS_VALUE;
- }
-
+ case Token.RETURN:
+ case Token.YIELD: {
+ pn = returnOrYield(tt, false);
break;
}
@@ -1241,6 +1206,58 @@ public class Parser
return pn;
}
+
+ private Node returnOrYield(int tt, boolean exprContext)
+ throws IOException, ParserException
+ {
+ if (!insideFunction()) {
+ reportError(tt == Token.RETURN ? "msg.bad.return"
+ : "msg.bad.yield");
+ }
+ consumeToken();
+ decompiler.addToken(tt);
+ int lineno = ts.getLineno();
+
+ Node e;
+ /* This is ugly, but we don't want to require a semicolon. */
+ switch (peekTokenOrEOL()) {
+ case Token.SEMI:
+ case Token.RC:
+ case Token.EOF:
+ case Token.EOL:
+ case Token.ERROR:
+ case Token.RB:
+ case Token.RP:
+ case Token.YIELD:
+ e = null;
+ break;
+ default:
+ e = expr(false);
+ break;
+ }
+ if (tt == Token.RETURN) {
+ // see if we need a strict mode warning
+ // TODO(js1.7gen): check for mixture of yield and value returns
+ if (e == null) {
+ if (functionEndFlags == Node.END_RETURNS_VALUE)
+ addStrictWarning("msg.return.inconsistent", "");
+
+ functionEndFlags |= Node.END_RETURNS;
+ } else {
+ hasReturnValue = true;
+ if (functionEndFlags == Node.END_RETURNS)
+ addStrictWarning("msg.return.inconsistent", "");
+
+ functionEndFlags |= Node.END_RETURNS_VALUE;
+ }
+ return nf.createReturn(e, lineno);
+ } else {
+ Node n = nf.createYield(e, lineno);
+ if (exprContext)
+ return n;
+ return new Node(Token.EXPR_VOID, n, lineno);
+ }
+ }
/**
* Parse a 'var' or 'const' statement, or a 'var' init list in a for
@@ -1321,6 +1338,9 @@ public class Parser
decompiler.addToken(Token.COMMA);
if (!pn.hasSideEffects())
addStrictWarning("msg.no.side.effects", "");
+ if (peekToken() == Token.YIELD) {
+ reportError("msg.yield.parenthesized");
+ }
pn = nf.createBinary(Token.COMMA, pn, assignExpr(inForInit));
}
return pn;
@@ -1329,9 +1349,14 @@ public class Parser
private Node assignExpr(boolean inForInit)
throws IOException, ParserException
{
+ int tt = peekToken();
+ if (tt == Token.YIELD) {
+ consumeToken();
+ return returnOrYield(tt, true);
+ }
Node pn = condExpr(inForInit);
- int tt = peekToken();
+ tt = peekToken();
if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) {
consumeToken();
decompiler.addToken(tt);
@@ -1687,6 +1712,9 @@ public class Parser
if (!first)
decompiler.addToken(Token.COMMA);
first = false;
+ if (peekToken() == Token.YIELD) {
+ reportError("msg.yield.parenthesized");
+ }
nf.addChildToBack(listNode, assignExpr(false));
} while (matchToken(Token.COMMA));
@@ -1769,6 +1797,13 @@ public class Parser
tt = nextToken();
switch (tt) {
+
+ // needed for generator.throw();
+ case Token.THROW:
+ decompiler.addName("throw");
+ pn = propertyName(pn, "throw", memberTypeFlags);
+ break;
+
// handles: name, ns::name, ns::*, ns::[expr]
case Token.NAME:
s = ts.getString();
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java b/mozilla/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
index 71ce92a0c44..4387e2b2422 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
@@ -202,6 +202,10 @@ public class ScriptRuntime {
NativeWith.init(scope, sealed);
NativeCall.init(scope, sealed);
NativeScript.init(scope, sealed);
+
+ // TODO(js1.7gen): jsshell marks generators as JSCLASS_IS_ANONYMOUS,
+ // meaning that "Generator" is not defined in the global scope
+ NativeGenerator.init(scope, sealed);
boolean withXml = cx.hasFeature(Context.FEATURE_E4X) && cx.getE4xImplementationFactory() != null;
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Token.java b/mozilla/js/rhino/src/org/mozilla/javascript/Token.java
index 7f7cdc2a2f0..43cd299fb5e 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/Token.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/Token.java
@@ -144,113 +144,115 @@ public class Token
DEL_REF = 67, // delete reference
REF_CALL = 68, // f(args) = something or f(args)++
REF_SPECIAL = 69, // reference for special properties like __proto
+ YIELD = 70, // JS 1.7 yield pseudo keyword
// For XML support:
- DEFAULTNAMESPACE = 70, // default xml namespace =
- ESCXMLATTR = 71,
- ESCXMLTEXT = 72,
- REF_MEMBER = 73, // Reference for x.@y, x..y etc.
- REF_NS_MEMBER = 74, // Reference for x.ns::y, x..ns::y etc.
- REF_NAME = 75, // Reference for @y, @[y] etc.
- REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc.
+ DEFAULTNAMESPACE = 71, // default xml namespace =
+ ESCXMLATTR = 72,
+ ESCXMLTEXT = 73,
+ REF_MEMBER = 74, // Reference for x.@y, x..y etc.
+ REF_NS_MEMBER = 75, // Reference for x.ns::y, x..ns::y etc.
+ REF_NAME = 76, // Reference for @y, @[y] etc.
+ REF_NS_NAME = 77; // Reference for ns::y, @ns::y@[y] etc.
// End of interpreter bytecodes
public final static int
LAST_BYTECODE_TOKEN = REF_NS_NAME,
- TRY = 77,
- SEMI = 78, // semicolon
- LB = 79, // left and right brackets
- RB = 80,
- LC = 81, // left and right curlies (braces)
- RC = 82,
- LP = 83, // left and right parentheses
- RP = 84,
- COMMA = 85, // comma operator
+ TRY = 78,
+ SEMI = 79, // semicolon
+ LB = 80, // left and right brackets
+ RB = 81,
+ LC = 82, // left and right curlies (braces)
+ RC = 83,
+ LP = 84, // left and right parentheses
+ RP = 85,
+ COMMA = 86, // comma operator
- ASSIGN = 86, // simple assignment (=)
- ASSIGN_BITOR = 87, // |=
- ASSIGN_BITXOR = 88, // ^=
- ASSIGN_BITAND = 89, // |=
- ASSIGN_LSH = 90, // <<=
- ASSIGN_RSH = 91, // >>=
- ASSIGN_URSH = 92, // >>>=
- ASSIGN_ADD = 93, // +=
- ASSIGN_SUB = 94, // -=
- ASSIGN_MUL = 95, // *=
- ASSIGN_DIV = 96, // /=
- ASSIGN_MOD = 97; // %=
+ ASSIGN = 87, // simple assignment (=)
+ ASSIGN_BITOR = 88, // |=
+ ASSIGN_BITXOR = 89, // ^=
+ ASSIGN_BITAND = 90, // |=
+ ASSIGN_LSH = 91, // <<=
+ ASSIGN_RSH = 92, // >>=
+ ASSIGN_URSH = 93, // >>>=
+ ASSIGN_ADD = 94, // +=
+ ASSIGN_SUB = 95, // -=
+ ASSIGN_MUL = 96, // *=
+ ASSIGN_DIV = 97, // /=
+ ASSIGN_MOD = 98; // %=
public final static int
FIRST_ASSIGN = ASSIGN,
LAST_ASSIGN = ASSIGN_MOD,
- HOOK = 98, // conditional (?:)
- COLON = 99,
- OR = 100, // logical or (||)
- AND = 101, // logical and (&&)
- INC = 102, // increment/decrement (++ --)
- DEC = 103,
- DOT = 104, // member operator (.)
- FUNCTION = 105, // function keyword
- EXPORT = 106, // export keyword
- IMPORT = 107, // import keyword
- IF = 108, // if keyword
- ELSE = 109, // else keyword
- SWITCH = 110, // switch keyword
- CASE = 111, // case keyword
- DEFAULT = 112, // default keyword
- WHILE = 113, // while keyword
- DO = 114, // do keyword
- FOR = 115, // for keyword
- BREAK = 116, // break keyword
- CONTINUE = 117, // continue keyword
- VAR = 118, // var keyword
- WITH = 119, // with keyword
- CATCH = 120, // catch keyword
- FINALLY = 121, // finally keyword
- VOID = 122, // void keyword
- RESERVED = 123, // reserved keywords
+ HOOK = 99, // conditional (?:)
+ COLON = 100,
+ OR = 101, // logical or (||)
+ AND = 102, // logical and (&&)
+ INC = 103, // increment/decrement (++ --)
+ DEC = 104,
+ DOT = 105, // member operator (.)
+ FUNCTION = 106, // function keyword
+ EXPORT = 107, // export keyword
+ IMPORT = 108, // import keyword
+ IF = 109, // if keyword
+ ELSE = 110, // else keyword
+ SWITCH = 111, // switch keyword
+ CASE = 112, // case keyword
+ DEFAULT = 113, // default keyword
+ WHILE = 114, // while keyword
+ DO = 115, // do keyword
+ FOR = 116, // for keyword
+ BREAK = 117, // break keyword
+ CONTINUE = 118, // continue keyword
+ VAR = 119, // var keyword
+ WITH = 120, // with keyword
+ CATCH = 121, // catch keyword
+ FINALLY = 122, // finally keyword
+ VOID = 123, // void keyword
+ RESERVED = 124, // reserved keywords
- EMPTY = 124,
+ EMPTY = 125,
/* types used for the parse tree - these never get returned
* by the scanner.
*/
- BLOCK = 125, // statement block
- LABEL = 126, // label
- TARGET = 127,
- LOOP = 128,
- EXPR_VOID = 129, // expression statement in functions
- EXPR_RESULT = 130, // expression statement in scripts
- JSR = 131,
- SCRIPT = 132, // top-level node for entire script
- TYPEOFNAME = 133, // for typeof(simple-name)
- USE_STACK = 134,
- SETPROP_OP = 135, // x.y op= something
- SETELEM_OP = 136, // x[y] op= something
- LOCAL_BLOCK = 137,
- SET_REF_OP = 138, // *reference op= something
+ BLOCK = 126, // statement block
+ LABEL = 127, // label
+ TARGET = 128,
+ LOOP = 129,
+ EXPR_VOID = 130, // expression statement in functions
+ EXPR_RESULT = 131, // expression statement in scripts
+ JSR = 132,
+ SCRIPT = 133, // top-level node for entire script
+ TYPEOFNAME = 134, // for typeof(simple-name)
+ USE_STACK = 135,
+ SETPROP_OP = 136, // x.y op= something
+ SETELEM_OP = 137, // x[y] op= something
+ LOCAL_BLOCK = 138,
+ SET_REF_OP = 139, // *reference op= something
// For XML support:
- DOTDOT = 139, // member operator (..)
- COLONCOLON = 140, // namespace::name
- XML = 141, // XML type
- DOTQUERY = 142, // .() -- e.g., x.emps.emp.(name == "terry")
- XMLATTR = 143, // @
- XMLEND = 144,
+ DOTDOT = 140, // member operator (..)
+ COLONCOLON = 141, // namespace::name
+ XML = 142, // XML type
+ DOTQUERY = 143, // .() -- e.g., x.emps.emp.(name == "terry")
+ XMLATTR = 144, // @
+ XMLEND = 145,
// Optimizer-only-tokens
- TO_OBJECT = 145,
- TO_DOUBLE = 146,
+ TO_OBJECT = 146,
+ TO_DOUBLE = 147,
- GET = 147, // JS 1.5 get pseudo keyword
- SET = 148, // JS 1.5 set pseudo keyword
- CONST = 149,
- SETCONST = 150,
- SETCONSTVAR = 151,
- LAST_TOKEN = 152;
+ GET = 148, // JS 1.5 get pseudo keyword
+ SET = 149, // JS 1.5 set pseudo keyword
+ LET = 150, // JS 1.7 let pseudo keyword
+ CONST = 151,
+ SETCONST = 152,
+ SETCONSTVAR = 153,
+ LAST_TOKEN = 154;
public static String name(int token)
{
@@ -407,6 +409,8 @@ public class Token
case TO_DOUBLE: return "TO_DOUBLE";
case GET: return "GET";
case SET: return "SET";
+ case LET: return "LET";
+ case YIELD: return "YIELD";
case CONST: return "CONST";
case SETCONST: return "SETCONST";
}
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/TokenStream.java b/mozilla/js/rhino/src/org/mozilla/javascript/TokenStream.java
index c276894b14f..39fa807d185 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/TokenStream.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/TokenStream.java
@@ -133,6 +133,7 @@ class TokenStream
Id_function = Token.FUNCTION,
Id_if = Token.IF,
Id_in = Token.IN,
+ Id_let = Token.LET,
Id_new = Token.NEW,
Id_null = Token.NULL,
Id_return = Token.RETURN,
@@ -144,6 +145,7 @@ class TokenStream
Id_void = Token.VOID,
Id_while = Token.WHILE,
Id_with = Token.WITH,
+ Id_yield = Token.YIELD,
// the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
Id_abstract = Token.RESERVED,
@@ -184,7 +186,7 @@ class TokenStream
int id;
String s = name;
-// #generated# Last update: 2001-06-01 17:45:01 CEST
+// #generated# Last update: 2007-04-18 13:53:30 PDT
L0: { id = 0; String X = null; int c;
L: switch (s.length()) {
case 2: c=s.charAt(1);
@@ -195,6 +197,7 @@ class TokenStream
case 3: switch (s.charAt(0)) {
case 'f': if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} break L;
case 'i': if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_int; break L0;} break L;
+ case 'l': if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_let; break L0;} break L;
case 'n': if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_new; break L0;} break L;
case 't': if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_try; break L0;} break L;
case 'v': if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_var; break L0;} break L;
@@ -221,7 +224,10 @@ class TokenStream
} break L;
case 5: switch (s.charAt(2)) {
case 'a': X="class";id=Id_class; break L;
- case 'e': X="break";id=Id_break; break L;
+ case 'e': c=s.charAt(0);
+ if (c=='b') { X="break";id=Id_break; }
+ else if (c=='y') { X="yield";id=Id_yield; }
+ break L;
case 'i': X="while";id=Id_while; break L;
case 'l': X="false";id=Id_false; break L;
case 'n': c=s.charAt(0);
@@ -394,6 +400,13 @@ class TokenStream
// Return the corresponding token if it's a keyword
int result = stringToKeyword(str);
if (result != Token.EOF) {
+ if ((result == Token.LET || result == Token.YIELD) &&
+ parser.compilerEnv.getLanguageVersion()
+ < Context.VERSION_1_7)
+ {
+ // LET and YIELD are tokens only in 1.7 and later
+ result = Token.NAME;
+ }
if (result != Token.RESERVED) {
return result;
} else if (!parser.compilerEnv.
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
index df8dcb46fda..5ac2a7f3c41 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
@@ -372,6 +372,10 @@ public class Codegen extends Interpreter
cfw.stopMethod((short)(firstLocal + 1));
}
+ // TODO(js1.7gen): make name a parameter, generalize to
+ // work for "call" and for "resumeGenerator".
+ // The "call" method should call "resumeGenerator" with a "start" operation
+ // (need to add "args" parameter to "resumeGenerator").
private void generateCallMethod(ClassFileWriter cfw)
{
cfw.startMethod("call",
@@ -1271,6 +1275,14 @@ class BodyCodegen
*/
private void generatePrologue()
{
+ /*
+ * TODO(js1.7gen):
+ * For resumeGenerator, generate prologue that looks at the value
+ * of the operation argument, does some setup, and jumps to the
+ * appropriate resumption point.
+ * Can assume inDirectCallFunction = false and hasVarsInRegs = false
+ * for generators.
+ */
if (inDirectCallFunction) {
int directParameterCount = scriptOrFn.getParamCount();
// 0 is reserved for function Object 'this'
@@ -2355,6 +2367,60 @@ class BodyCodegen
+")Ljava/lang/Object;");
break;
+ case Token.YIELD:
+ /*
+ * TODO(js1.7gen): Generate code to save the execution state
+ * of the JVM. This may not be too bad: since generators
+ * require an activation, all variables are in the activation
+ * object. Look through the prologue code at the java
+ * registers that are initialized. Look to see if any of those
+ * values are altered during execution; if not, you can
+ * just rely on shared prologue code for the generator.
+ * Hardest part will be the stack. You'll need to create a
+ * compile-time data structure that tracks the type of every
+ * element on the stack. Then when you generate code for the
+ * yield, you'll generate code to take the contents of the
+ * stack and save it to an in-memory object (Object[] or pair
+ * of Object[] double[], I'm not sure which). You'll also
+ * need the inverse operation of taking an object like that
+ * and pushing all its saved values onto the stack. It may
+ * make sense to alter ClassFileWriter to maintain stack
+ * information, or maintain a parallel data structure in
+ * Codegen.
+ *
+ * Each yield point will need to have a unique integer number
+ * determined at compile time. When a program encounters a
+ * yield, the yield number will be saved in the state object.
+ * The "resumeGenerator" prologue code will need to have a
+ * code to take the integer and then jump to the appropriate
+ * yield. You'll need to run the validator with yields in
+ * various points in control flow to make sure that the
+ * validator doesn't object to these jumps into the middle of
+ * various control structures. I think it should be okay since
+ * the register save code will ensure that you never jump
+ * into a place with different stack height or uninitialized
+ * variables.
+ *
+ * The biggest unknown area for me is exception handling.
+ * There are cases of yields in finally clauses that suspend
+ * a function with an in-flight exception. It may have to be
+ * that Rhino doesn't generate any finally clauses but instead
+ * catches all exceptions, processes finally clauses (including
+ * yields) and rethrows. Then in-flight exceptions will just
+ * be variables that can be captured. The other question is
+ * whether the validator will object to jumps in and out of
+ * try and catch blocks.
+ *
+ * Probably don't need analog to Icode_GENERATOR: all setup
+ * code can be handled in "resumeGenerator" prologue.
+ *
+ * Probably do need analog to Icode_GENERATOR_END. Perhaps
+ * during code generation for returns, can check to see if
+ * in generator and if so generate code for the analog
+ * to Icode_GENERATOR_END.
+ */
+ break;
+
default:
throw new RuntimeException("Unexpected node type "+type);
}
diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/resources/Messages.properties b/mozilla/js/rhino/src/org/mozilla/javascript/resources/Messages.properties
index b4d0c38a7ee..90df7fe548e 100644
--- a/mozilla/js/rhino/src/org/mozilla/javascript/resources/Messages.properties
+++ b/mozilla/js/rhino/src/org/mozilla/javascript/resources/Messages.properties
@@ -126,6 +126,12 @@ msg.bad.decr =\
msg.bad.incr =\
Invalid increment operand.
+msg.bad.yield =\
+ yield must be in a function.
+
+msg.yield.parenthesized =\
+ yield expression must be parenthesized.
+
# NativeGlobal
msg.cant.call.indirect =\
Function "{0}" must be called directly, and not by way of a \
@@ -448,7 +454,7 @@ msg.assn.create.strict =\
Assignment to undeclared variable {0}
msg.ref.undefined.prop =\
- Referenced to undefined property "{0}"
+ Referenced to undefined property "{0}"
msg.prop.not.found =\
Property {0} not found.
@@ -691,3 +697,14 @@ msg.bad.uri =\
# Number
msg.bad.precision =\
Precision {0} out of range.
+
+# NativeGenerator
+msg.send.newborn =\
+ Attempt to send value to newborn generator
+
+msg.already.exec.gen =\
+ Already executing generator
+
+# Interpreter
+msg.yield.closing =\
+ Yield from closing generator
diff --git a/mozilla/js/rhino/testsrc/base.skip b/mozilla/js/rhino/testsrc/base.skip
index 553584c15fa..e15e7cf181b 100644
--- a/mozilla/js/rhino/testsrc/base.skip
+++ b/mozilla/js/rhino/testsrc/base.skip
@@ -167,8 +167,29 @@ js1_7/geniter/regress-347739.js
js1_7/geniter/regress-349012-01.js
js1_7/geniter/regress-349331.js
+# Generator functionality not yet implemented:
+# "Iterator" constructor
+js1_7/geniter/builtin-Iterator-function.js
+# array comprehensions
+js1_7/geniter/regress-345736.js
+# let statements
+js1_7/geniter/regress-347593.js
+# yield and xml-filtering predicate
+js1_7/geniter/regress-352605.js
+# destructuring assignment
+js1_7/geniter/regress-366941.js
+# for (i in )
+js1_7/geniter/regress-350621.js
+
# JS 1.7 not yet implemented
-js1_7
+js1_7/block
+js1_7/decompilation
+js1_7/expressions
+js1_7/extensions
+js1_7/iterable
+js1_7/lexical
+js1_7/regexp
+js1_7/regress
# JS 1.8 not yet implemented
js1_8
diff --git a/mozilla/js/rhino/testsrc/opt1.skip b/mozilla/js/rhino/testsrc/opt1.skip
index e1607e6c337..70068826188 100644
--- a/mozilla/js/rhino/testsrc/opt1.skip
+++ b/mozilla/js/rhino/testsrc/opt1.skip
@@ -13,11 +13,14 @@ js1_5/Regress/regress-80981.js
js1_5/Regress/regress-89443.js
js1_5/extensions/regress-226507.js
-# Needs investigation
-#js1_5/Exceptions/regress-257751.js
-#js1_5/Regress/regress-111557.js
-#js1_5/Regress/regress-155081-2.js
-#js1_5/Regress/regress-155081.js
-#js1_5/Regress/regress-167328.js
-#js1_5/extensions/regress-50447.js
-#js1_5/extensions/regress-311161.js
+# program too large/complex; could have better error message
+js1_5/Regress/regress-111557.js
+js1_5/Regress/regress-155081-2.js
+js1_5/Regress/regress-155081.js
+js1_5/extensions/regress-311161.js
+
+# Missing line number information on error
+js1_5/Regress/regress-167328.js
+js1_5/extensions/regress-50447.js
+js1_5/Exceptions/regress-257751.js
+
diff --git a/mozilla/js/rhino/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties b/mozilla/js/rhino/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
index 119dd851454..4009efc94fd 100644
--- a/mozilla/js/rhino/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
+++ b/mozilla/js/rhino/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
@@ -57,7 +57,7 @@ msg.shell.usage =\
Valid options are:\n\
\ -?, -help Displays help messages.\n\
\ -w Enable warnings.\n\
- \ -version 100|110|120|130|140|150|160\n\
+ \ -version 100|110|120|130|140|150|160|170\n\
\ Set a specific language version.\n\
\ -opt [-1|0-9] Set optimization level.\n\
\ -f script-filename Execute script file.\n\
@@ -66,7 +66,6 @@ msg.shell.usage =\
\ -strict Enable strict mode warnings.\n\
\ -fatal-warnings Treat warnings as errors.
-
msg.help =\
\n\
Command Description \n\