8143304: Random failures when script size exceeds token limits
Reviewed-by: sundar, attila, lagergren
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Nov 19 14:37:14 2015 +0100
@@ -3323,9 +3323,6 @@
if (needsScope) {
method.loadCompilerConstant(SCOPE);
- }
-
- if (needsScope) {
loadExpressionUnbounded(init);
// block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Thu Nov 19 14:37:14 2015 +0100
@@ -103,6 +103,9 @@
* @param lineOffset Offset from which lines should be counted
*/
protected AbstractParser(final Source source, final ErrorManager errors, final boolean strict, final int lineOffset) {
+ if (source.getLength() > Token.LENGTH_MASK) {
+ throw new RuntimeException("Source exceeds size limit of " + Token.LENGTH_MASK + " bytes");
+ }
this.source = source;
this.errors = errors;
this.k = -1;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Thu Nov 19 14:37:14 2015 +0100
@@ -213,7 +213,6 @@
* function body. This is used with the feature where the parser is skipping nested function bodies to
* avoid reading ahead unnecessarily when we skip the function bodies.
*/
-
public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
super(source.getContent(), 1, start, len);
this.source = source;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java Thu Nov 19 14:37:14 2015 +0100
@@ -30,11 +30,21 @@
import jdk.nashorn.internal.runtime.Source;
/**
- * Basic parse/lex unit.
- *
+ * A token is a 64 bit long value that represents a basic parse/lex unit.
+ * This class provides static methods to manipulate lexer tokens.
*/
public class Token {
+ /**
+ * We use 28 bits for the position and 28 bits for the length of the token.
+ * This limits the maximal length of code we can handle to 2 ^ 28 - 1 bytes.
+ */
+ public final static int LENGTH_MASK = 0xfffffff;
+
+ // The first 8 bits are used for the token type, followed by length and position
+ private final static int LENGTH_SHIFT = 8;
+ private final static int POSITION_SHIFT = 36;
+
private Token() {
}
@@ -46,8 +56,9 @@
* @return Token descriptor.
*/
public static long toDesc(final TokenType type, final int position, final int length) {
- return (long)position << 32 |
- (long)length << 8 |
+ assert position <= LENGTH_MASK && length <= LENGTH_MASK;
+ return (long)position << POSITION_SHIFT |
+ (long)length << LENGTH_SHIFT |
type.ordinal();
}
@@ -57,7 +68,7 @@
* @return Start position of the token in the source.
*/
public static int descPosition(final long token) {
- return (int)(token >>> 32);
+ return (int)(token >>> POSITION_SHIFT);
}
/**
@@ -98,7 +109,7 @@
* @return Length of the token.
*/
public static int descLength(final long token) {
- return (int)token >>> 8;
+ return (int)((token >>> LENGTH_SHIFT) & LENGTH_MASK);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8059934.js Thu Nov 19 14:37:14 2015 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8059934: Random failures when script size exceeds token limits
+ *
+ * @test
+ * @run
+ */
+
+// Make sure that we can successfully evaluate a 100 MB string.
+// We don't go beyond that as we'd likely hit heap size limits.
+var src = "var x = 'ok';";
+for (var i = 0; i < 1000000; i++) {
+ src += " ";
+}
+src += "x;";
+
+Assert.assertEquals(100000015, src.length);
+Assert.assertEquals("ok", eval(src));
+