diff options
Diffstat (limited to 'src/jdk/nashorn')
52 files changed, 1217 insertions, 531 deletions
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 283e36e9..b05a4aee 100644 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -34,6 +34,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.lang.reflect.Method; import java.net.URL; +import java.nio.charset.Charset; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; @@ -72,7 +73,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private final ScriptObject global; // default options passed to Nashorn Options object - private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-af", "-doe" }; + private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" }; NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) { this(factory, DEFAULT_OPTIONS, appLoader); @@ -121,7 +122,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C try { if (reader instanceof URLReader) { final URL url = ((URLReader)reader).getURL(); - return evalImpl(compileImpl(new Source(url.toString(), url), ctxt), ctxt); + final Charset cs = ((URLReader)reader).getCharset(); + return evalImpl(compileImpl(new Source(url.toString(), url, cs), ctxt), ctxt); } return evalImpl(Source.readFully(reader), ctxt); } catch (final IOException e) { diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 7428a8f6..79e908db 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -342,6 +342,184 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { }); } + // Support for ECMAScript Object API on mirrors + + /** + * Return the __proto__ of this object. + * @return __proto__ object. + */ + public Object getProto() { + return inGlobal(new Callable<Object>() { + @Override public Object call() { + return wrap(getScriptObject().getProto(), global); + } + }); + } + + /** + * ECMA 8.12.1 [[GetOwnProperty]] (P) + * + * @param key property key + * + * @return Returns the Property Descriptor of the named own property of this + * object, or undefined if absent. + */ + public Object getOwnPropertyDescriptor(final String key) { + return inGlobal(new Callable<Object>() { + @Override public Object call() { + return wrap(getScriptObject().getOwnPropertyDescriptor(key), global); + } + }); + } + + /** + * return an array of own property keys associated with the object. + * + * @param all True if to include non-enumerable keys. + * @return Array of keys. + */ + public String[] getOwnKeys(final boolean all) { + return inGlobal(new Callable<String[]>() { + @Override public String[] call() { + return getScriptObject().getOwnKeys(all); + } + }); + } + + /** + * Flag this script object as non extensible + * + * @return the object after being made non extensible + */ + public ScriptObjectMirror preventExtensions() { + return inGlobal(new Callable<ScriptObjectMirror>() { + @Override public ScriptObjectMirror call() { + getScriptObject().preventExtensions(); + return ScriptObjectMirror.this; + } + }); + } + + /** + * Check if this script object is extensible + * @return true if extensible + */ + public boolean isExtensible() { + return inGlobal(new Callable<Boolean>() { + @Override public Boolean call() { + return getScriptObject().isExtensible(); + } + }); + } + + /** + * ECMAScript 15.2.3.8 - seal implementation + * @return the sealed script object + */ + public ScriptObjectMirror seal() { + return inGlobal(new Callable<ScriptObjectMirror>() { + @Override public ScriptObjectMirror call() { + getScriptObject().seal(); + return ScriptObjectMirror.this; + } + }); + } + + /** + * Check whether this script object is sealed + * @return true if sealed + */ + public boolean isSealed() { + return inGlobal(new Callable<Boolean>() { + @Override public Boolean call() { + return getScriptObject().isSealed(); + } + }); + } + + /** + * ECMA 15.2.39 - freeze implementation. Freeze this script object + * @return the frozen script object + */ + public ScriptObjectMirror freeze() { + return inGlobal(new Callable<ScriptObjectMirror>() { + @Override public ScriptObjectMirror call() { + getScriptObject().freeze(); + return ScriptObjectMirror.this; + } + }); + } + + /** + * Check whether this script object is frozen + * @return true if frozen + */ + public boolean isFrozen() { + return inGlobal(new Callable<Boolean>() { + @Override public Boolean call() { + return getScriptObject().isFrozen(); + } + }); + } + + // ECMAScript instanceof check + + /** + * Checking whether a script object is an instance of another by + * walking the proto chain + * + * @param instance instace to check + * @return true if 'instance' is an instance of this object + */ + public boolean isInstance(final ScriptObjectMirror instance) { + // if not belongs to my global scope, return false + if (instance == null || global != instance.global) { + return false; + } + + return inGlobal(new Callable<Boolean>() { + @Override public Boolean call() { + return getScriptObject().isInstance(instance.getScriptObject()); + } + }); + } + + /** + * Utility to check if given object is ECMAScript undefined value + * + * @param obj object to check + * @return true if 'obj' is ECMAScript undefined value + */ + public static boolean isUndefined(final Object obj) { + return obj == ScriptRuntime.UNDEFINED; + } + + /** + * is this a function object? + * + * @return if this mirror wraps a ECMAScript function instance + */ + public boolean isFunction() { + return getScriptObject() instanceof ScriptFunction; + } + + /** + * is this a 'use strict' function object? + * + * @return true if this mirror represents a ECMAScript 'use strict' function + */ + public boolean isStrictFunction() { + return isFunction() && ((ScriptFunction)getScriptObject()).isStrict(); + } + + /** + * is this an array object? + * + * @return if this mirror wraps a ECMAScript array object + */ + public boolean isArray() { + return getScriptObject().isArray(); + } // These are public only so that Context can access these. diff --git a/src/jdk/nashorn/api/scripting/URLReader.java b/src/jdk/nashorn/api/scripting/URLReader.java index d21d6263..13f69843 100644 --- a/src/jdk/nashorn/api/scripting/URLReader.java +++ b/src/jdk/nashorn/api/scripting/URLReader.java @@ -25,10 +25,12 @@ package jdk.nashorn.api.scripting; +import java.io.CharArrayReader; import java.io.IOException; -import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; +import java.nio.charset.Charset; +import jdk.nashorn.internal.runtime.Source; /** * A Reader that reads from a URL. Used to make sure that the reader @@ -36,7 +38,10 @@ import java.net.URL; */ public final class URLReader extends Reader { // underlying URL - private URL url; + private final URL url; + // Charset used to convert + private final Charset cs; + // lazily initialized underlying reader for URL private Reader reader; @@ -44,9 +49,35 @@ public final class URLReader extends Reader { * Constructor * * @param url URL for this URLReader + * @throws NullPointerException if url is null */ public URLReader(final URL url) { + this(url, (Charset)null); + } + + /** + * Constructor + * + * @param url URL for this URLReader + * @param charsetName Name of the Charset used to convert bytes to chars + * @throws NullPointerException if url is null + */ + public URLReader(final URL url, final String charsetName) { + this(url, Charset.forName(charsetName)); + } + + /** + * Constructor + * + * @param url URL for this URLReader + * @param cs Charset used to convert bytes to chars + * @throws NullPointerException if url is null + */ + public URLReader(final URL url, final Charset cs) { + // null check + url.getClass(); this.url = url; + this.cs = cs; } @Override @@ -67,11 +98,20 @@ public final class URLReader extends Reader { return url; } + /** + * Charset used by this reader + * + * @return the Chartset used to convert bytes to chars + */ + public Charset getCharset() { + return cs; + } + // lazily initialize char array reader using URL content private Reader getReader() throws IOException { synchronized (lock) { if (reader == null) { - reader = new InputStreamReader(url.openStream()); + reader = new CharArrayReader(Source.readFully(url, cs)); } } diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java index d0b5a00a..3a442a7d 100644 --- a/src/jdk/nashorn/internal/codegen/Attr.java +++ b/src/jdk/nashorn/internal/codegen/Attr.java @@ -35,6 +35,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; +import static jdk.nashorn.internal.ir.Symbol.IS_ALWAYS_DEFINED; import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF; import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; @@ -128,6 +129,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { private final Deque<Type> returnTypes; + private int catchNestingLevel; + private static final DebugLogger LOG = new DebugLogger("attr"); private static final boolean DEBUG = LOG.isEnabled(); @@ -169,14 +172,14 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { if (functionNode.isVarArg()) { initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY); if (functionNode.needsArguments()) { - initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); + initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class)); addLocalDef(ARGUMENTS.symbolName()); } } initParameters(functionNode, body); - initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); - initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, Type.OBJECT); + initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class)); + initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.OBJECT); } @@ -202,18 +205,52 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables, except function declarations (which are taken care // in a separate step above) and "var" declarations in for loop initializers. + // + // It also handles the case that a variable can be undefined, e.g + // if (cond) { + // x = x.y; + // } + // var x = 17; + // + // by making sure that no identifier has been found earlier in the body than the + // declaration - if such is the case the identifier is flagged as caBeUndefined to + // be safe if it turns into a local var. Otherwise corrupt bytecode results + body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { + private final Set<String> uses = new HashSet<>(); + private final Set<String> canBeUndefined = new HashSet<>(); + @Override public boolean enterFunctionNode(final FunctionNode nestedFn) { return false; } @Override + public Node leaveIdentNode(final IdentNode identNode) { + uses.add(identNode.getName()); + return identNode; + } + + @Override + public boolean enterVarNode(final VarNode varNode) { + final String name = varNode.getName().getName(); + //if this is used the var node symbol needs to be tagged as can be undefined + if (uses.contains(name)) { + canBeUndefined.add(name); + } + return true; + } + + @Override public Node leaveVarNode(final VarNode varNode) { // any declared symbols that aren't visited need to be typed as well, hence the list if (varNode.isStatement()) { final IdentNode ident = varNode.getName(); final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR); + if (canBeUndefined.contains(ident.getName())) { + symbol.setType(Type.OBJECT); + symbol.setCanBeUndefined(); + } functionNode.addDeclaredSymbol(symbol); if (varNode.isFunctionDeclaration()) { newType(symbol, FunctionNode.FUNCTION_TYPE); @@ -286,10 +323,12 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { final Block block = lc.getCurrentBlock(); start(catchNode); + catchNestingLevel++; // define block-local exception variable - final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET); - newType(def, Type.OBJECT); + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET | IS_ALWAYS_DEFINED); + newType(def, Type.OBJECT); //we can catch anything, not just ecma exceptions + addLocalDef(exception.getName()); return true; @@ -300,6 +339,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { final IdentNode exception = catchNode.getException(); final Block block = lc.getCurrentBlock(); final Symbol symbol = findSymbol(block, exception.getName()); + + catchNestingLevel--; + assert symbol != null; return end(catchNode.setException((IdentNode)exception.setSymbol(lc, symbol))); } @@ -509,9 +551,19 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { assert lc.getFunctionBody(functionNode).getExistingSymbol(CALLEE.symbolName()) != null; lc.setFlag(functionNode.getBody(), Block.NEEDS_SELF_SYMBOL); newType(symbol, FunctionNode.FUNCTION_TYPE); - } else if (!identNode.isInitializedHere()) { // NASHORN-448 - // here is a use outside the local def scope - if (!isLocalDef(name)) { + } else if (!identNode.isInitializedHere()) { + /* + * See NASHORN-448, JDK-8016235 + * + * Here is a use outside the local def scope + * the inCatch check is a conservative approach to handle things that might have only been + * defined in the try block, but with variable declarations, which due to JavaScript rules + * have to be lifted up into the function scope outside the try block anyway, but as the + * flow can fault at almost any place in the try block and get us to the catch block, all we + * know is that we have a declaration, not a definition. This can be made better and less + * conservative once we superimpose a CFG onto the AST. + */ + if (!isLocalDef(name) || inCatch()) { newType(symbol, Type.OBJECT); symbol.setCanBeUndefined(); } @@ -538,6 +590,10 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { return end(identNode.setSymbol(lc, symbol)); } + private boolean inCatch() { + return catchNestingLevel > 0; + } + /** * If the symbol isn't already a scope symbol, and it is either not local to the current function, or it is being * referenced from within a with block, we force it to be a scope symbol. @@ -550,26 +606,26 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { } private boolean symbolNeedsToBeScope(Symbol symbol) { - if(symbol.isThis() || symbol.isInternal()) { + if (symbol.isThis() || symbol.isInternal()) { return false; } boolean previousWasBlock = false; - for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { + for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); - if(node instanceof FunctionNode) { + if (node instanceof FunctionNode) { // We reached the function boundary without seeing a definition for the symbol - it needs to be in // scope. return true; - } else if(node instanceof WithNode) { - if(previousWasBlock) { + } else if (node instanceof WithNode) { + if (previousWasBlock) { // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately // preceded by a block, this means we're currently processing its expression, not its body, // therefore it doesn't count. return true; } previousWasBlock = false; - } else if(node instanceof Block) { - if(((Block)node).getExistingSymbol(symbol.getName()) == symbol) { + } else if (node instanceof Block) { + if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) { // We reached the block that defines the symbol without reaching either the function boundary, or a // WithNode. The symbol need not be scoped. return false; @@ -1666,8 +1722,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> { } private void pushLocalsBlock() { - localDefs.push(localDefs.isEmpty() ? new HashSet<String>() : new HashSet<>(localDefs.peek())); - localUses.push(localUses.isEmpty() ? new HashSet<String>() : new HashSet<>(localUses.peek())); + localDefs.push(new HashSet<>(localDefs.peek())); + localUses.push(new HashSet<>(localUses.peek())); } private void popLocals() { diff --git a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java index 16ad2709..974b5ba8 100644 --- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java +++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java @@ -126,7 +126,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator { final T value = valueIter.next(); if (symbol != null && value != null) { - final int index = ArrayIndex.getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (index < 0) { putField(method, key, symbol.getFieldIndex(), value); diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java index 153e0367..609fac9b 100644 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -79,7 +79,7 @@ public class MapCreator { final String key = keys[i]; final Symbol symbol = symbols[i]; - if (symbol != null && !ArrayIndex.isIndexKey(key)) { + if (symbol != null && !ArrayIndex.isIntArrayIndex(key)) { properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex())); } } diff --git a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java index a86a327e..71c80a6b 100644 --- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java +++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java @@ -63,6 +63,7 @@ public class BlockLexicalContext extends LexicalContext { return sstack.pop(); } + @SuppressWarnings("unchecked") @Override public <T extends LexicalContextNode> T pop(final T node) { T expected = node; diff --git a/src/jdk/nashorn/internal/ir/BreakableNode.java b/src/jdk/nashorn/internal/ir/BreakableNode.java index ea07cb4b..171df8e3 100644 --- a/src/jdk/nashorn/internal/ir/BreakableNode.java +++ b/src/jdk/nashorn/internal/ir/BreakableNode.java @@ -86,7 +86,7 @@ public abstract class BreakableNode extends LexicalContextNode { /** * Return the labels associated with this node. Breakable nodes that - * aren't LoopNodes only have a break label -> the location immediately + * aren't LoopNodes only have a break label - the location immediately * afterwards the node in code * @return list of labels representing locations around this node */ diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java index d26fe561..7c183902 100644 --- a/src/jdk/nashorn/internal/ir/Symbol.java +++ b/src/jdk/nashorn/internal/ir/Symbol.java @@ -55,23 +55,25 @@ public final class Symbol implements Comparable<Symbol> { public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits /** Is this scope */ - public static final int IS_SCOPE = 1 << 4; + public static final int IS_SCOPE = 1 << 4; /** Is this a this symbol */ - public static final int IS_THIS = 1 << 5; + public static final int IS_THIS = 1 << 5; /** Can this symbol ever be undefined */ - public static final int CAN_BE_UNDEFINED = 1 << 6; + public static final int CAN_BE_UNDEFINED = 1 << 6; + /** Is this symbol always defined? */ + public static final int IS_ALWAYS_DEFINED = 1 << 8; /** Can this symbol ever have primitive types */ - public static final int CAN_BE_PRIMITIVE = 1 << 7; + public static final int CAN_BE_PRIMITIVE = 1 << 9; /** Is this a let */ - public static final int IS_LET = 1 << 8; + public static final int IS_LET = 1 << 10; /** Is this an internal symbol, never represented explicitly in source code */ - public static final int IS_INTERNAL = 1 << 9; + public static final int IS_INTERNAL = 1 << 11; /** Is this a function self-reference symbol */ - public static final int IS_FUNCTION_SELF = 1 << 10; + public static final int IS_FUNCTION_SELF = 1 << 12; /** Is this a specialized param? */ - public static final int IS_SPECIALIZED_PARAM = 1 << 11; + public static final int IS_SPECIALIZED_PARAM = 1 << 13; /** Is this symbol a shared temporary? */ - public static final int IS_SHARED = 1 << 12; + public static final int IS_SHARED = 1 << 14; /** Null or name identifying symbol. */ private final String name; @@ -384,7 +386,7 @@ public final class Symbol implements Comparable<Symbol> { * Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary. */ public void setIsShared() { - if(!isShared()) { + if (!isShared()) { assert isTemp(); trace("SET IS SHARED"); flags |= IS_SHARED; @@ -417,6 +419,14 @@ public final class Symbol implements Comparable<Symbol> { } /** + * Check if this symbol is always defined, which overrides all canBeUndefined tags + * @return true if always defined + */ + public boolean isAlwaysDefined() { + return isParam() || (flags & IS_ALWAYS_DEFINED) == IS_ALWAYS_DEFINED; + } + + /** * Get the range for this symbol * @return range for symbol */ @@ -462,7 +472,9 @@ public final class Symbol implements Comparable<Symbol> { */ public void setCanBeUndefined() { assert type.isObject() : type; - if(!canBeUndefined()) { + if (isAlwaysDefined()) { + return; + } else if (!canBeUndefined()) { assert !isShared(); flags |= CAN_BE_UNDEFINED; } diff --git a/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java index 73397b59..59660ae6 100644 --- a/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java +++ b/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java @@ -138,18 +138,16 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = isStrictContext(); - if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); } else { - delete(CONFIGURABLE, strict); + delete(CONFIGURABLE, false); } if (sobj.has(ENUMERABLE)) { this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE)); } else { - delete(ENUMERABLE, strict); + delete(ENUMERABLE, false); } if (sobj.has(GET)) { @@ -160,7 +158,7 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr throw typeError("not.a.function", ScriptRuntime.safeToString(getter)); } } else { - delete(GET, strict); + delete(GET, false); } if (sobj.has(SET)) { @@ -171,7 +169,7 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr throw typeError("not.a.function", ScriptRuntime.safeToString(setter)); } } else { - delete(SET, strict); + delete(SET, false); } return this; diff --git a/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/src/jdk/nashorn/internal/objects/ArrayBufferView.java index d85b31cb..2011daeb 100644 --- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java +++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java @@ -33,6 +33,8 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.arrays.ArrayData; +import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; + @ScriptClass("ArrayBufferView") abstract class ArrayBufferView extends ScriptObject { @@ -305,11 +307,11 @@ abstract class ArrayBufferView extends ScriptObject { dst = factory.construct(length); } else if (arg0 instanceof NativeArray) { // Constructor(type[] array) - length = (int) (((NativeArray) arg0).getArray().length() & 0x7fff_ffff); + length = lengthToInt(((NativeArray) arg0).getArray().length()); dst = factory.construct(length); } else { // Constructor(unsigned long length) - length = JSType.toInt32(arg0); + length = lengthToInt(JSType.toInt64(arg0)); return factory.construct(length); } @@ -354,6 +356,13 @@ abstract class ArrayBufferView extends ScriptObject { } } + private static int lengthToInt(final long length) { + if (length > Integer.MAX_VALUE || length < 0) { + throw rangeError("inappropriate.array.buffer.length", JSType.toString(length)); + } + return (int) (length & Integer.MAX_VALUE); + } + protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) { final ArrayBufferView arrayView = ((ArrayBufferView)self); final int elementLength = arrayView.elementLength(); diff --git a/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java index e5f7de31..7ce4d85e 100644 --- a/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java +++ b/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java @@ -136,29 +136,28 @@ public final class DataPropertyDescriptor extends ScriptObject implements Proper @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = isStrictContext(); if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); } else { - delete(CONFIGURABLE, strict); + delete(CONFIGURABLE, false); } if (sobj.has(ENUMERABLE)) { this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE)); } else { - delete(ENUMERABLE, strict); + delete(ENUMERABLE, false); } if (sobj.has(WRITABLE)) { this.writable = JSType.toBoolean(sobj.get(WRITABLE)); } else { - delete(WRITABLE, strict); + delete(WRITABLE, false); } if (sobj.has(VALUE)) { this.value = sobj.get(VALUE); } else { - delete(VALUE, strict); + delete(VALUE, false); } return this; diff --git a/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java b/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java index 31afc307..8f2be7c8 100644 --- a/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java +++ b/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java @@ -124,17 +124,16 @@ public final class GenericPropertyDescriptor extends ScriptObject implements Pro @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = isStrictContext(); if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); } else { - delete(CONFIGURABLE, strict); + delete(CONFIGURABLE, false); } if (sobj.has(ENUMERABLE)) { this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE)); } else { - delete(ENUMERABLE, strict); + delete(ENUMERABLE, false); } return this; diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 04daa8b5..59a9dd34 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -37,6 +37,7 @@ import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -372,7 +373,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class); private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class); private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class); - private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object.class); + private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class); private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class); private final Context context; @@ -429,15 +430,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return instance().context; } - /** - * Script access check for strict mode - * - * @return true if strict mode enabled in {@link Global#getThisContext()} - */ - static boolean isStrict() { - return getEnv()._strict; - } - // GlobalObject interface implementation @Override @@ -615,14 +607,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set); - final boolean strict = context.getEnv()._strict; - if (get == null) { - desc.delete(PropertyDescriptor.GET, strict); + desc.delete(PropertyDescriptor.GET, false); } if (set == null) { - desc.delete(PropertyDescriptor.SET, strict); + desc.delete(PropertyDescriptor.SET, false); } return desc; @@ -750,16 +740,21 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { /** * Global loadWithNewGlobal implementation - Nashorn extension * - * @param self scope - * @param source source to load + * @param self scope + * @param args from plus (optional) arguments to be passed to the loaded script * - * @return result of load (undefined) + * @return result of load (may be undefined) * * @throws IOException if source could not be read */ - public static Object loadWithNewGlobal(final Object self, final Object source) throws IOException { + public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { final Global global = Global.instance(); - return global.context.loadWithNewGlobal(source); + final int length = args.length; + final boolean hasArgs = 0 < length; + final Object from = hasArgs ? args[0] : UNDEFINED; + final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; + + return global.context.loadWithNewGlobal(from, arguments); } /** @@ -1479,7 +1474,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // Error objects this.builtinError = (ScriptFunction)initConstructor("Error"); final ScriptObject errorProto = getErrorPrototype(); - final boolean strict = Global.isStrict(); // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK); @@ -1497,10 +1491,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // ECMA 15.11.4.2 Error.prototype.name // Error.prototype.name = "Error"; - errorProto.set(NativeError.NAME, "Error", strict); + errorProto.set(NativeError.NAME, "Error", false); // ECMA 15.11.4.3 Error.prototype.message // Error.prototype.message = ""; - errorProto.set(NativeError.MESSAGE, "", strict); + errorProto.set(NativeError.MESSAGE, "", false); this.builtinEvalError = initErrorSubtype("EvalError", errorProto); this.builtinRangeError = initErrorSubtype("RangeError", errorProto); @@ -1513,9 +1507,8 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { final ScriptObject cons = initConstructor(name); final ScriptObject prototype = ScriptFunction.getPrototype(cons); - final boolean strict = Global.isStrict(); - prototype.set(NativeError.NAME, name, strict); - prototype.set(NativeError.MESSAGE, "", strict); + prototype.set(NativeError.NAME, name, false); + prototype.set(NativeError.MESSAGE, "", false); prototype.setProto(errorProto); return (ScriptFunction)cons; } @@ -1724,7 +1717,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // <anon-function> builtinFunction.setProto(anon); builtinFunction.setPrototype(anon); - anon.set("constructor", builtinFunction, anon.isStrict()); + anon.set("constructor", builtinFunction, false); anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); // now initialize Object diff --git a/src/jdk/nashorn/internal/objects/NativeArguments.java b/src/jdk/nashorn/internal/objects/NativeArguments.java index efab674b..d92d7fb3 100644 --- a/src/jdk/nashorn/internal/objects/NativeArguments.java +++ b/src/jdk/nashorn/internal/objects/NativeArguments.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow; import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; @@ -132,103 +131,103 @@ public final class NativeArguments extends ScriptObject { @Override public int getInt(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); } @Override public int getInt(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); } @Override public int getInt(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); } @Override public int getInt(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); } @Override public long getLong(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); } @Override public long getLong(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); } @Override public long getLong(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); } @Override public long getLong(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); } @Override public double getDouble(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); } @Override public double getDouble(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); } @Override public double getDouble(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); } @Override public double getDouble(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); } @Override public Object get(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getObject(index) : super.get(key); } @Override public Object get(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getObject(index) : super.get(key); } @Override public Object get(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getObject(index) : super.get(key); } @Override public Object get(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) ? namedArgs.getObject(index) : super.get(key); } @Override public void set(final Object key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -238,7 +237,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final Object key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -248,7 +247,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final Object key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -258,7 +257,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final Object key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -268,7 +267,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final double key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -278,7 +277,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final double key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -288,7 +287,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final double key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -298,7 +297,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final double key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -308,7 +307,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final long key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -318,7 +317,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final long key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -328,7 +327,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final long key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -338,7 +337,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final long key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -348,7 +347,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final int key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -358,7 +357,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final int key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -368,7 +367,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final int key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -378,7 +377,7 @@ public final class NativeArguments extends ScriptObject { @Override public void set(final int key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (isMapped(index)) { namedArgs = namedArgs.set(index, value, strict); } else { @@ -388,55 +387,55 @@ public final class NativeArguments extends ScriptObject { @Override public boolean has(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.has(key); } @Override public boolean has(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.has(key); } @Override public boolean has(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.has(key); } @Override public boolean has(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.has(key); } @Override public boolean hasOwnProperty(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.hasOwnProperty(key); } @Override public boolean hasOwnProperty(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.hasOwnProperty(key); } @Override public boolean hasOwnProperty(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.hasOwnProperty(key); } @Override public boolean hasOwnProperty(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isMapped(index) || super.hasOwnProperty(key); } @Override public boolean delete(final int key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final boolean success = super.delete(key, strict); if (success && namedArgs.has(index)) { setDeleted(index); @@ -446,7 +445,7 @@ public final class NativeArguments extends ScriptObject { @Override public boolean delete(final long key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final boolean success = super.delete(key, strict); if (success && namedArgs.has(index)) { setDeleted(index); @@ -456,7 +455,7 @@ public final class NativeArguments extends ScriptObject { @Override public boolean delete(final double key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final boolean success = super.delete(key, strict); if (success && namedArgs.has(index)) { setDeleted(index); @@ -466,7 +465,7 @@ public final class NativeArguments extends ScriptObject { @Override public boolean delete(final Object key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final boolean success = super.delete(key, strict); if (success && namedArgs.has(index)) { setDeleted(index); @@ -480,7 +479,7 @@ public final class NativeArguments extends ScriptObject { */ @Override public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) { - final int index = ArrayIndex.getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (index >= 0) { final boolean allowed = super.defineOwnProperty(key, propertyDesc, false); if (!allowed) { diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index 9736376b..a480c590 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -118,7 +119,7 @@ public final class NativeArray extends ScriptObject { if (value == ScriptRuntime.EMPTY) { arrayData = arrayData.delete(index); } else { - arrayData = arrayData.set(index, value, isStrictContext()); + arrayData = arrayData.set(index, value, false); } } @@ -158,6 +159,11 @@ public final class NativeArray extends ScriptObject { // Step 3 if ("length".equals(key)) { + // check for length being made non-writable + if (desc.has(WRITABLE) && !desc.isWritable()) { + setIsLengthNotWritable(); + } + // Step 3a if (!desc.has(VALUE)) { return super.defineOwnProperty("length", desc, reject); @@ -228,7 +234,7 @@ public final class NativeArray extends ScriptObject { } // Step 4a - final int index = ArrayIndex.getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (ArrayIndex.isValidArrayIndex(index)) { final long longIndex = ArrayIndex.toLongIndex(index); // Step 4b @@ -286,7 +292,8 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isArray(final Object self, final Object arg) { return isArray(arg) || (arg == Global.instance().getArrayPrototype()) - || (arg instanceof NativeRegExpExecResult); + || (arg instanceof NativeRegExpExecResult) + || (arg instanceof ScriptObjectMirror && ((ScriptObjectMirror)arg).isArray()); } /** @@ -603,7 +610,6 @@ public final class NativeArray extends ScriptObject { public static Object pop(final Object self) { try { final ScriptObject sobj = (ScriptObject)self; - final boolean strict = sobj.isStrictContext(); if (bulkable(sobj)) { return sobj.getArray().pop(); @@ -612,15 +618,15 @@ public final class NativeArray extends ScriptObject { final long len = JSType.toUint32(sobj.getLength()); if (len == 0) { - sobj.set("length", 0, strict); + sobj.set("length", 0, true); return ScriptRuntime.UNDEFINED; } final long index = len - 1; final Object element = sobj.get(index); - sobj.delete(index, strict); - sobj.set("length", index, strict); + sobj.delete(index, true); + sobj.set("length", index, true); return element; } catch (final ClassCastException | NullPointerException e) { @@ -639,11 +645,10 @@ public final class NativeArray extends ScriptObject { public static Object push(final Object self, final Object... args) { try { final ScriptObject sobj = (ScriptObject)self; - final boolean strict = sobj.isStrictContext(); if (bulkable(sobj)) { if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) { - final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args); + final ArrayData newData = sobj.getArray().push(true, args); sobj.setArray(newData); return newData.length(); } @@ -652,9 +657,9 @@ public final class NativeArray extends ScriptObject { long len = JSType.toUint32(sobj.getLength()); for (final Object element : args) { - sobj.set(len++, element, strict); + sobj.set(len++, element, true); } - sobj.set("length", len, strict); + sobj.set("length", len, true); return len; } catch (final ClassCastException | NullPointerException e) { @@ -672,7 +677,6 @@ public final class NativeArray extends ScriptObject { public static Object reverse(final Object self) { try { final ScriptObject sobj = (ScriptObject)self; - final boolean strict = sobj.isStrictContext(); final long len = JSType.toUint32(sobj.getLength()); final long middle = len / 2; @@ -684,14 +688,14 @@ public final class NativeArray extends ScriptObject { final boolean upperExists = sobj.has(upper); if (lowerExists && upperExists) { - sobj.set(lower, upperValue, strict); - sobj.set(upper, lowerValue, strict); + sobj.set(lower, upperValue, true); + sobj.set(upper, lowerValue, true); } else if (!lowerExists && upperExists) { - sobj.set(lower, upperValue, strict); - sobj.delete(upper, strict); + sobj.set(lower, upperValue, true); + sobj.delete(upper, true); } else if (lowerExists && !upperExists) { - sobj.delete(lower, strict); - sobj.set(upper, lowerValue, strict); + sobj.delete(lower, true); + sobj.set(upper, lowerValue, true); } } return sobj; @@ -717,7 +721,6 @@ public final class NativeArray extends ScriptObject { } final ScriptObject sobj = (ScriptObject) obj; - final boolean strict = Global.isStrict(); long len = JSType.toUint32(sobj.getLength()); @@ -728,15 +731,15 @@ public final class NativeArray extends ScriptObject { sobj.getArray().shiftLeft(1); } else { for (long k = 1; k < len; k++) { - sobj.set(k - 1, sobj.get(k), strict); + sobj.set(k - 1, sobj.get(k), true); } } - sobj.delete(--len, strict); + sobj.delete(--len, true); } else { len = 0; } - sobj.set("length", len, strict); + sobj.set("length", len, true); return first; } @@ -770,7 +773,7 @@ public final class NativeArray extends ScriptObject { final NativeArray copy = new NativeArray(0); for (long n = 0; k < finale; n++, k++) { - copy.defineOwnProperty((int) n, sobj.get(k)); + copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k)); } return copy; @@ -833,30 +836,27 @@ public final class NativeArray extends ScriptObject { public static Object sort(final Object self, final Object comparefn) { try { final ScriptObject sobj = (ScriptObject) self; - final boolean strict = sobj.isStrictContext(); final long len = JSType.toUint32(sobj.getLength()); + ArrayData array = sobj.getArray(); if (len > 1) { // Get only non-missing elements. Missing elements go at the end // of the sorted array. So, just don't copy these to sort input. - final ArrayList<Object> src = new ArrayList<>(); - for (int i = 0; i < (int)len; i++) { - if (sobj.has(i)) { - src.add(sobj.get(i)); + for (long i = 0; i < len; i = array.nextIndex(i)) { + if (array.has((int) i)) { + src.add(array.getObject((int) i)); } } final Object[] sorted = sort(src.toArray(), comparefn); for (int i = 0; i < sorted.length; i++) { - sobj.set(i, sorted[i], strict); + array = array.set(i, sorted[i], true); } // delete missing elements - which are at the end of sorted array - for (int j = sorted.length; j < (int)len; j++) { - sobj.delete(j, strict); - } + sobj.setArray(array.delete(sorted.length, len - 1)); } return sobj; @@ -893,7 +893,6 @@ public final class NativeArray extends ScriptObject { } final ScriptObject sobj = (ScriptObject)obj; - final boolean strict = Global.isStrict(); final long len = JSType.toUint32(sobj.getLength()); final long relativeStart = JSType.toLong(start); @@ -906,7 +905,7 @@ public final class NativeArray extends ScriptObject { final long from = actualStart + k; if (sobj.has(from)) { - array.defineOwnProperty((int) k, sobj.get(from)); + array.defineOwnProperty(ArrayIndex.getArrayIndex(k), sobj.get(from)); } } @@ -916,14 +915,14 @@ public final class NativeArray extends ScriptObject { final long to = k + items.length; if (sobj.has(from)) { - sobj.set(to, sobj.get(from), strict); + sobj.set(to, sobj.get(from), true); } else { - sobj.delete(to, strict); + sobj.delete(to, true); } } for (long k = len; k > (len - actualDeleteCount + items.length); k--) { - sobj.delete(k - 1, strict); + sobj.delete(k - 1, true); } } else if (items.length > actualDeleteCount) { for (long k = len - actualDeleteCount; k > actualStart; k--) { @@ -932,20 +931,20 @@ public final class NativeArray extends ScriptObject { if (sobj.has(from)) { final Object fromValue = sobj.get(from); - sobj.set(to, fromValue, strict); + sobj.set(to, fromValue, true); } else { - sobj.delete(to, strict); + sobj.delete(to, true); } } } long k = actualStart; for (int i = 0; i < items.length; i++, k++) { - sobj.set(k, items[i], strict); + sobj.set(k, items[i], true); } final long newLength = len - actualDeleteCount + items.length; - sobj.set("length", newLength, strict); + sobj.set("length", newLength, true); return array; } @@ -966,7 +965,6 @@ public final class NativeArray extends ScriptObject { } final ScriptObject sobj = (ScriptObject)obj; - final boolean strict = Global.isStrict(); final long len = JSType.toUint32(sobj.getLength()); if (items == null) { @@ -977,7 +975,7 @@ public final class NativeArray extends ScriptObject { sobj.getArray().shiftRight(items.length); for (int j = 0; j < items.length; j++) { - sobj.setArray(sobj.getArray().set(j, items[j], sobj.isStrictContext())); + sobj.setArray(sobj.getArray().set(j, items[j], true)); } } else { for (long k = len; k > 0; k--) { @@ -986,19 +984,19 @@ public final class NativeArray extends ScriptObject { if (sobj.has(from)) { final Object fromValue = sobj.get(from); - sobj.set(to, fromValue, strict); + sobj.set(to, fromValue, true); } else { - sobj.delete(to, strict); + sobj.delete(to, true); } } for (int j = 0; j < items.length; j++) { - sobj.set(j, items[j], strict); + sobj.set(j, items[j], true); } } final long newLength = len + items.length; - sobj.set("length", newLength, strict); + sobj.set("length", newLength, true); return newLength; } @@ -1143,7 +1141,7 @@ public final class NativeArray extends ScriptObject { @Override protected boolean forEach(final Object val, final long i) throws Throwable { final Object r = MAP_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self); - result.defineOwnProperty((int)index, r); + result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r); return true; } @@ -1172,7 +1170,7 @@ public final class NativeArray extends ScriptObject { @Override protected boolean forEach(final Object val, final long i) throws Throwable { if ((boolean)FILTER_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)) { - result.defineOwnProperty((int)(to++), val); + result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val); } return true; } @@ -1241,7 +1239,7 @@ public final class NativeArray extends ScriptObject { * @return true if optimizable */ private static boolean bulkable(final ScriptObject self) { - return self.isArray() && !hasInheritedArrayEntries(self); + return self.isArray() && !hasInheritedArrayEntries(self) && !self.isLengthNotWritable(); } private static boolean hasInheritedArrayEntries(final ScriptObject self) { diff --git a/src/jdk/nashorn/internal/objects/NativeError.java b/src/jdk/nashorn/internal/objects/NativeError.java index 5473c8ef..b10a1c40 100644 --- a/src/jdk/nashorn/internal/objects/NativeError.java +++ b/src/jdk/nashorn/internal/objects/NativeError.java @@ -90,7 +90,7 @@ public final class NativeError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } @@ -166,7 +166,7 @@ public final class NativeError extends ScriptObject { public static Object setLineNumber(final Object self, final Object value) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; - sobj.set(LINENUMBER, value, Global.isStrict()); + sobj.set(LINENUMBER, value, false); return value; } @@ -194,7 +194,7 @@ public final class NativeError extends ScriptObject { public static Object setColumnNumber(final Object self, final Object value) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; - sobj.set(COLUMNNUMBER, value, Global.isStrict()); + sobj.set(COLUMNNUMBER, value, false); return value; } @@ -222,7 +222,7 @@ public final class NativeError extends ScriptObject { public static Object setFileName(final Object self, final Object value) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; - sobj.set(FILENAME, value, Global.isStrict()); + sobj.set(FILENAME, value, false); return value; } @@ -278,7 +278,7 @@ public final class NativeError extends ScriptObject { public static Object setStack(final Object self, final Object value) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; - sobj.set(STACK, value, Global.isStrict()); + sobj.set(STACK, value, false); return value; } diff --git a/src/jdk/nashorn/internal/objects/NativeEvalError.java b/src/jdk/nashorn/internal/objects/NativeEvalError.java index a33fb0db..c4fc838e 100644 --- a/src/jdk/nashorn/internal/objects/NativeEvalError.java +++ b/src/jdk/nashorn/internal/objects/NativeEvalError.java @@ -59,7 +59,7 @@ public final class NativeEvalError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java index 528b120a..38ead325 100644 --- a/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.util.List; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -102,6 +103,16 @@ public final class NativeFunction { list.toArray(args = new Object[list.size()]); } else if (array == null || array == UNDEFINED) { args = ScriptRuntime.EMPTY_ARRAY; + } else if (array instanceof ScriptObjectMirror) { + // look for array-like ScriptObjectMirror object + final ScriptObjectMirror mirror = (ScriptObjectMirror)array; + final Object len = mirror.containsKey("length")? mirror.getMember("length") : Integer.valueOf(0); + final int n = (int)JSType.toUint32(len); + + args = new Object[n]; + for (int i = 0; i < args.length; i++) { + args[i] = mirror.containsKey(i)? mirror.getSlot(i) : UNDEFINED; + } } else { throw typeError("function.apply.expects.array"); } @@ -216,7 +227,7 @@ public final class NativeFunction { final Global global = Global.instance(); - return Global.directEval(global, sb.toString(), global, "<function>", Global.isStrict()); + return Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext()); } private static void checkFunctionParameters(final String params) { diff --git a/src/jdk/nashorn/internal/objects/NativeJSON.java b/src/jdk/nashorn/internal/objects/NativeJSON.java index b3d6d873..ec35fc4e 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSON.java +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java @@ -158,7 +158,7 @@ public final class NativeJSON extends ScriptObject { state.gap = gap; final ScriptObject wrapper = Global.newEmptyInstance(); - wrapper.set("", value, Global.isStrict()); + wrapper.set("", value, false); return str("", wrapper, state); } diff --git a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index 88d0e6a3..82849172 100644 --- a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -121,7 +121,7 @@ public final class NativeJavaImporter extends ScriptObject { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final Object value = createProperty(name); if(value != null) { - set(name, value, isStrictContext()); + set(name, value, false); return true; } return false; diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 5162d89b..20a69039 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -28,11 +28,13 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -54,6 +56,10 @@ public final class NativeObject { private NativeObject() { } + private static ECMAException notAnObject(final Object obj) { + return typeError("not.an.object", ScriptRuntime.safeToString(obj)); + } + /** * ECMA 15.2.3.2 Object.getPrototypeOf ( O ) * @@ -63,9 +69,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getPrototypeOf(final Object self, final Object obj) { - Global.checkObject(obj); - - return ((ScriptObject)obj).getProto(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).getProto(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).getProto(); + } else { + throw notAnObject(obj); + } } /** @@ -78,12 +88,19 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) { - Global.checkObject(obj); + if (obj instanceof ScriptObject) { + final String key = JSType.toString(prop); + final ScriptObject sobj = (ScriptObject)obj; - final String key = JSType.toString(prop); - final ScriptObject sobj = (ScriptObject)obj; + return sobj.getOwnPropertyDescriptor(key); + } else if (obj instanceof ScriptObjectMirror) { + final String key = JSType.toString(prop); + final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj; - return sobj.getOwnPropertyDescriptor(key); + return sobjMirror.getOwnPropertyDescriptor(key); + } else { + throw notAnObject(obj); + } } /** @@ -95,9 +112,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getOwnPropertyNames(final Object self, final Object obj) { - Global.checkObject(obj); - - return new NativeArray(((ScriptObject)obj).getOwnKeys(true)); + if (obj instanceof ScriptObject) { + return new NativeArray(((ScriptObject)obj).getOwnKeys(true)); + } else if (obj instanceof ScriptObjectMirror) { + return new NativeArray(((ScriptObjectMirror)obj).getOwnKeys(true)); + } else { + throw notAnObject(obj); + } } /** @@ -175,8 +196,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object seal(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).seal(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).seal(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).seal(); + } else { + throw notAnObject(obj); + } } @@ -189,8 +215,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object freeze(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).freeze(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).freeze(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).freeze(); + } else { + throw notAnObject(obj); + } } /** @@ -202,8 +233,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object preventExtensions(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).preventExtensions(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).preventExtensions(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).preventExtensions(); + } else { + throw notAnObject(obj); + } } /** @@ -215,8 +251,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isSealed(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).isSealed(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).isSealed(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).isSealed(); + } else { + throw notAnObject(obj); + } } /** @@ -228,8 +269,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isFrozen(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).isFrozen(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).isFrozen(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).isFrozen(); + } else { + throw notAnObject(obj); + } } /** @@ -241,8 +287,13 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isExtensible(final Object self, final Object obj) { - Global.checkObject(obj); - return ((ScriptObject)obj).isExtensible(); + if (obj instanceof ScriptObject) { + return ((ScriptObject)obj).isExtensible(); + } else if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)obj).isExtensible(); + } else { + throw notAnObject(obj); + } } /** @@ -254,9 +305,15 @@ public final class NativeObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object keys(final Object self, final Object obj) { - Global.checkObject(obj); - final ScriptObject sobj = (ScriptObject)obj; - return new NativeArray(sobj.getOwnKeys(false)); + if (obj instanceof ScriptObject) { + final ScriptObject sobj = (ScriptObject)obj; + return new NativeArray(sobj.getOwnKeys(false)); + } else if (obj instanceof ScriptObjectMirror) { + final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj; + return new NativeArray(sobjMirror.getOwnKeys(false)); + } else { + throw notAnObject(obj); + } } /** diff --git a/src/jdk/nashorn/internal/objects/NativeRangeError.java b/src/jdk/nashorn/internal/objects/NativeRangeError.java index dcdd517e..1dcb4f27 100644 --- a/src/jdk/nashorn/internal/objects/NativeRangeError.java +++ b/src/jdk/nashorn/internal/objects/NativeRangeError.java @@ -59,7 +59,7 @@ public final class NativeRangeError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/src/jdk/nashorn/internal/objects/NativeReferenceError.java index a3ae89e8..7bff7796 100644 --- a/src/jdk/nashorn/internal/objects/NativeReferenceError.java +++ b/src/jdk/nashorn/internal/objects/NativeReferenceError.java @@ -59,7 +59,7 @@ public final class NativeReferenceError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk/nashorn/internal/objects/NativeRegExp.java index 8b469bc1..bbbd9791 100644 --- a/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -641,26 +641,19 @@ public final class NativeRegExp extends ScriptObject { return string; } - /* - * $$ -> $ - * $& -> the matched substring - * $` -> the portion of string that preceeds matched substring - * $' -> the portion of string that follows the matched substring - * $n -> the nth capture, where n is [1-9] and $n is NOT followed by a decimal digit - * $nn -> the nnth capture, where nn is a two digit decimal number [01-99]. - */ - String replace = replacement; - if (!regexp.isGlobal()) { if (!matcher.search(0)) { return string; } final StringBuilder sb = new StringBuilder(); + sb.append(string, 0, matcher.start()); + if (function != null) { - replace = callReplaceValue(function, matcher, string); + sb.append(callReplaceValue(function, matcher, string)); + } else { + appendReplacement(matcher, string, replacement, sb); } - appendReplacement(matcher, string, replace, sb, 0); sb.append(string, matcher.end(), string.length()); return sb.toString(); } @@ -676,12 +669,13 @@ public final class NativeRegExp extends ScriptObject { final StringBuilder sb = new StringBuilder(); do { + sb.append(string, thisIndex, matcher.start()); if (function != null) { - replace = callReplaceValue(function, matcher, string); + sb.append(callReplaceValue(function, matcher, string)); + } else { + appendReplacement(matcher, string, replacement, sb); } - appendReplacement(matcher, string, replace, sb, thisIndex); - // ECMA 15.5.4.10 String.prototype.match(regexp) thisIndex = matcher.end(); if (thisIndex == previousLastIndex) { @@ -697,10 +691,19 @@ public final class NativeRegExp extends ScriptObject { return sb.toString(); } - private void appendReplacement(final RegExpMatcher matcher, final String text, final String replacement, final StringBuilder sb, final int lastAppendPosition) { - // Process substitution string to replace group references with groups + private void appendReplacement(final RegExpMatcher matcher, final String text, final String replacement, final StringBuilder sb) { + /* + * Process substitution patterns: + * + * $$ -> $ + * $& -> the matched substring + * $` -> the portion of string that preceeds matched substring + * $' -> the portion of string that follows the matched substring + * $n -> the nth capture, where n is [1-9] and $n is NOT followed by a decimal digit + * $nn -> the nnth capture, where nn is a two digit decimal number [01-99]. + */ + int cursor = 0; - final StringBuilder result = new StringBuilder(); Object[] groups = null; while (cursor < replacement.length()) { @@ -732,37 +735,33 @@ public final class NativeRegExp extends ScriptObject { } // Append group if matched. if (groups[refNum] != UNDEFINED) { - result.append((String) groups[refNum]); + sb.append((String) groups[refNum]); } } else { // $0. ignore. assert refNum == 0; - result.append("$0"); + sb.append("$0"); } } else if (nextChar == '$') { - result.append('$'); + sb.append('$'); cursor++; } else if (nextChar == '&') { - result.append(matcher.group()); + sb.append(matcher.group()); cursor++; } else if (nextChar == '`') { - result.append(text.substring(0, matcher.start())); + sb.append(text, 0, matcher.start()); cursor++; } else if (nextChar == '\'') { - result.append(text.substring(matcher.end())); + sb.append(text, matcher.end(), text.length()); cursor++; } else { // unknown substitution or $n with n>m. skip. - result.append('$'); + sb.append('$'); } } else { - result.append(nextChar); + sb.append(nextChar); cursor++; } } - // Append the intervening text - sb.append(text, lastAppendPosition, matcher.start()); - // Append the match substitution - sb.append(result); } private String callReplaceValue(final ScriptFunction function, final RegExpMatcher matcher, final String string) { diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java index df4aa1bf..fda265e6 100644 --- a/src/jdk/nashorn/internal/objects/NativeString.java +++ b/src/jdk/nashorn/internal/objects/NativeString.java @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -156,7 +155,7 @@ public final class NativeString extends ScriptObject { @SuppressWarnings("unused") private static Object get(final Object self, final Object key) { final CharSequence cs = JSType.toCharSequence(self); - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (index >= 0 && index < cs.length()) { return String.valueOf(cs.charAt(index)); } @@ -191,7 +190,7 @@ public final class NativeString extends ScriptObject { // String characters can be accessed with array-like indexing.. @Override public Object get(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (index >= 0 && index < value.length()) { return String.valueOf(value.charAt(index)); } @@ -284,7 +283,7 @@ public final class NativeString extends ScriptObject { @Override public boolean has(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.has(key); } @@ -295,19 +294,19 @@ public final class NativeString extends ScriptObject { @Override public boolean has(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.has(key); } @Override public boolean has(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.has(key); } @Override public boolean hasOwnProperty(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.hasOwnProperty(key); } @@ -318,13 +317,13 @@ public final class NativeString extends ScriptObject { @Override public boolean hasOwnProperty(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.hasOwnProperty(key); } @Override public boolean hasOwnProperty(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return isValid(index) || super.hasOwnProperty(key); } @@ -335,19 +334,19 @@ public final class NativeString extends ScriptObject { @Override public boolean delete(final long key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return checkDeleteIndex(index, strict)? false : super.delete(key, strict); } @Override public boolean delete(final double key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return checkDeleteIndex(index, strict)? false : super.delete(key, strict); } @Override public boolean delete(final Object key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); return checkDeleteIndex(index, strict)? false : super.delete(key, strict); } @@ -364,7 +363,7 @@ public final class NativeString extends ScriptObject { @Override public Object getOwnPropertyDescriptor(final String key) { - final int index = ArrayIndex.getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (index >= 0 && index < value.length()) { final Global global = Global.instance(); return global.newDataDescriptor(String.valueOf(value.charAt(index)), false, true, false); diff --git a/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/src/jdk/nashorn/internal/objects/NativeSyntaxError.java index db54c483..e9ec3050 100644 --- a/src/jdk/nashorn/internal/objects/NativeSyntaxError.java +++ b/src/jdk/nashorn/internal/objects/NativeSyntaxError.java @@ -59,7 +59,7 @@ public final class NativeSyntaxError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/objects/NativeTypeError.java b/src/jdk/nashorn/internal/objects/NativeTypeError.java index 5e87fbb2..bbec5ad3 100644 --- a/src/jdk/nashorn/internal/objects/NativeTypeError.java +++ b/src/jdk/nashorn/internal/objects/NativeTypeError.java @@ -59,7 +59,7 @@ public final class NativeTypeError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - delete(NativeError.MESSAGE, Global.isStrict()); + delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/objects/NativeURIError.java b/src/jdk/nashorn/internal/objects/NativeURIError.java index 958c14ac..e6c91525 100644 --- a/src/jdk/nashorn/internal/objects/NativeURIError.java +++ b/src/jdk/nashorn/internal/objects/NativeURIError.java @@ -58,7 +58,7 @@ public final class NativeURIError extends ScriptObject { if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { - this.delete(NativeError.MESSAGE, Global.isStrict()); + this.delete(NativeError.MESSAGE, false); } } diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java index aa9234ef..f1e68f66 100644 --- a/src/jdk/nashorn/internal/parser/JSONParser.java +++ b/src/jdk/nashorn/internal/parser/JSONParser.java @@ -54,10 +54,9 @@ public class JSONParser extends AbstractParser { * Constructor * @param source the source * @param errors the error manager - * @param strict are we in strict mode */ - public JSONParser(final Source source, final ErrorManager errors, final boolean strict) { - super(source, errors, strict); + public JSONParser(final Source source, final ErrorManager errors) { + super(source, errors, false); } /** @@ -135,6 +134,7 @@ public class JSONParser extends AbstractParser { return ch == '\"'; } + // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONWhiteSpace @Override protected boolean isWhitespace(final char ch) { return Lexer.isJsonWhitespace(ch); @@ -144,6 +144,99 @@ public class JSONParser extends AbstractParser { protected boolean isEOL(final char ch) { return Lexer.isJsonEOL(ch); } + + // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONNumber + @Override + protected void scanNumber() { + // Record beginning of number. + final int startPosition = position; + // Assume value is a decimal. + TokenType valueType = TokenType.DECIMAL; + + // floating point can't start with a "." with no leading digit before + if (ch0 == '.') { + error(Lexer.message("json.invalid.number"), STRING, position, limit); + } + + // First digit of number. + int digit = convertDigit(ch0, 10); + + // skip first digit + skip(1); + + if (digit != 0) { + // Skip over remaining digits. + while (convertDigit(ch0, 10) != -1) { + skip(1); + } + } + + if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') { + // Must be a double. + if (ch0 == '.') { + // Skip period. + skip(1); + + boolean mantissa = false; + // Skip mantissa. + while (convertDigit(ch0, 10) != -1) { + mantissa = true; + skip(1); + } + + if (! mantissa) { + // no digit after "." + error(Lexer.message("json.invalid.number"), STRING, position, limit); + } + } + + // Detect exponent. + if (ch0 == 'E' || ch0 == 'e') { + // Skip E. + skip(1); + // Detect and skip exponent sign. + if (ch0 == '+' || ch0 == '-') { + skip(1); + } + boolean exponent = false; + // Skip exponent. + while (convertDigit(ch0, 10) != -1) { + exponent = true; + skip(1); + } + + if (! exponent) { + // no digit after "E" + error(Lexer.message("json.invalid.number"), STRING, position, limit); + } + } + + valueType = TokenType.FLOATING; + } + + // Add number token. + add(valueType, startPosition); + } + + // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONEscapeCharacter + @Override + protected boolean isEscapeCharacter(final char ch) { + switch (ch) { + case '"': + case '/': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + // could be unicode escape + case 'u': + return true; + default: + return false; + } + } }; k = -1; diff --git a/src/jdk/nashorn/internal/parser/Lexer.java b/src/jdk/nashorn/internal/parser/Lexer.java index d9ebb365..ecf67962 100644 --- a/src/jdk/nashorn/internal/parser/Lexer.java +++ b/src/jdk/nashorn/internal/parser/Lexer.java @@ -648,7 +648,7 @@ public class Lexer extends Scanner { * * @return The converted digit or -1 if invalid. */ - private static int convertDigit(final char ch, final int base) { + protected static int convertDigit(final char ch, final int base) { int digit; if ('0' <= ch && ch <= '9') { @@ -666,37 +666,24 @@ public class Lexer extends Scanner { /** - * Get the value of a numeric sequence. - * - * @param base Numeric base. - * @param max Maximum number of digits. - * @param skip Skip over escape first. - * @param check Tells whether to throw error if a digit is invalid for the given base. - * @param type Type of token to report against. + * Get the value of a hexadecimal numeric sequence. * + * @param length Number of digits. + * @param type Type of token to report against. * @return Value of sequence or < 0 if no digits. */ - private int valueOfSequence(final int base, final int max, final boolean skip, final boolean check, final TokenType type) { - assert base == 16 || base == 8 : "base other than 16 or 8"; - final boolean isHex = base == 16; - final int shift = isHex ? 4 : 3; + private int hexSequence(final int length, final TokenType type) { int value = 0; - if (skip) { - skip(2); - } - - for (int i = 0; i < max; i++) { - final int digit = convertDigit(ch0, base); + for (int i = 0; i < length; i++) { + final int digit = convertDigit(ch0, 16); if (digit == -1) { - if (check) { - error(Lexer.message("invalid." + (isHex ? "hex" : "octal")), type, position, limit); - } + error(Lexer.message("invalid.hex"), type, position, limit); return i == 0 ? -1 : value; } - value = value << shift | digit; + value = digit | value << 4; skip(1); } @@ -704,6 +691,30 @@ public class Lexer extends Scanner { } /** + * Get the value of an octal numeric sequence. This parses up to 3 digits with a maximum value of 255. + * + * @return Value of sequence. + */ + private int octalSequence() { + int value = 0; + + for (int i = 0; i < 3; i++) { + final int digit = convertDigit(ch0, 8); + + if (digit == -1) { + break; + } + value = digit | value << 3; + skip(1); + + if (i == 1 && value >= 32) { + break; + } + } + return value; + } + + /** * Convert a string to a JavaScript identifier. * * @param start Position in source content. @@ -724,7 +735,8 @@ public class Lexer extends Scanner { while (!atEOF() && position < end && !isEOL(ch0)) { // If escape character. if (ch0 == '\\' && ch1 == 'u') { - final int ch = valueOfSequence(16, 4, true, true, TokenType.IDENT); + skip(2); + final int ch = hexSequence(4, TokenType.IDENT); if (isWhitespace((char)ch)) { return null; } @@ -815,7 +827,7 @@ public class Lexer extends Scanner { } reset(afterSlash); // Octal sequence. - final int ch = valueOfSequence(8, 3, false, false, STRING); + final int ch = octalSequence(); if (ch < 0) { sb.append('\\'); @@ -862,7 +874,7 @@ public class Lexer extends Scanner { break; case 'x': { // Hex sequence. - final int ch = valueOfSequence(16, 2, false, true, STRING); + final int ch = hexSequence(2, STRING); if (ch < 0) { sb.append('\\'); @@ -874,7 +886,7 @@ public class Lexer extends Scanner { break; case 'u': { // Unicode sequence. - final int ch = valueOfSequence(16, 4, false, true, STRING); + final int ch = hexSequence(4, STRING); if (ch < 0) { sb.append('\\'); @@ -907,8 +919,9 @@ public class Lexer extends Scanner { /** * Scan over a string literal. + * @param add true if we nare not just scanning but should actually modify the token stream */ - private void scanString(final boolean add) { + protected void scanString(final boolean add) { // Type of string. TokenType type = STRING; // Record starting quote. @@ -925,6 +938,9 @@ public class Lexer extends Scanner { if (ch0 == '\\') { type = ESCSTRING; skip(1); + if (! isEscapeCharacter(ch0)) { + error(Lexer.message("invalid.escape.char"), STRING, position, limit); + } if (isEOL(ch0)) { // Multiline string literal skipEOL(false); @@ -979,6 +995,16 @@ public class Lexer extends Scanner { } /** + * Is the given character a valid escape char after "\" ? + * + * @param ch character to be checked + * @return if the given character is valid after "\" + */ + protected boolean isEscapeCharacter(final char ch) { + return true; + } + + /** * Convert string to number. * * @param valueString String to convert. @@ -1024,7 +1050,7 @@ public class Lexer extends Scanner { /** * Scan a number. */ - private void scanNumber() { + protected void scanNumber() { // Record beginning of number. final int start = position; // Assume value is a decimal. @@ -1090,6 +1116,10 @@ public class Lexer extends Scanner { } } + if (Character.isJavaIdentifierStart(ch0)) { + error(Lexer.message("missing.space.after.number"), type, position, 1); + } + // Add number token. add(type, start); } @@ -1178,7 +1208,8 @@ public class Lexer extends Scanner { // Make sure first character is valid start character. if (ch0 == '\\' && ch1 == 'u') { - final int ch = valueOfSequence(16, 4, true, true, TokenType.IDENT); + skip(2); + final int ch = hexSequence(4, TokenType.IDENT); if (!Character.isJavaIdentifierStart(ch)) { error(Lexer.message("illegal.identifier.character"), TokenType.IDENT, start, position); @@ -1191,7 +1222,8 @@ public class Lexer extends Scanner { // Make sure remaining characters are valid part characters. while (!atEOF()) { if (ch0 == '\\' && ch1 == 'u') { - final int ch = valueOfSequence(16, 4, true, true, TokenType.IDENT); + skip(2); + final int ch = hexSequence(4, TokenType.IDENT); if (!Character.isJavaIdentifierPart(ch)) { error(Lexer.message("illegal.identifier.character"), TokenType.IDENT, start, position); @@ -1583,7 +1615,13 @@ public class Lexer extends Scanner { return null; } - private static String message(final String msgId, final String... args) { + /** + * Get the correctly localized error message for a given message id format arguments + * @param msgId message id + * @param args format arguments + * @return message + */ + protected static String message(final String msgId, final String... args) { return ECMAErrors.getMessage("lexer.error." + msgId, args); } diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index ee90b8d9..0c2c1633 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -2403,7 +2403,7 @@ loop: verifyStrictIdent(name, "function name"); } else if (isStatement) { // Nashorn extension: anonymous function statements - if (env._no_syntax_extensions || !env._anon_functions) { + if (env._no_syntax_extensions) { expect(IDENT); } } diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index d0e3b020..5b89ec2c 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -46,6 +46,7 @@ import java.security.CodeSource; import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; +import java.util.Map; import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ScriptObjectMirror; @@ -188,7 +189,7 @@ public final class Context { private final ScriptEnvironment env; /** is this context in strict mode? Cached from env. as this is used heavily. */ - public final boolean _strict; + final boolean _strict; /** class loader to resolve classes from script. */ private final ClassLoader appLoader; @@ -482,6 +483,13 @@ public final class Context { final String name = JSType.toString(sobj.get("name")); source = new Source(name, script); } + } else if (src instanceof Map) { + final Map map = (Map)src; + if (map.containsKey("script") && map.containsKey("name")) { + final String script = JSType.toString(map.get("script")); + final String name = JSType.toString(map.get("name")); + source = new Source(name, script); + } } if (source != null) { @@ -496,12 +504,13 @@ public final class Context { * expression, after creating a new global scope. * * @param from source expression for script + * @param args (optional) arguments to be passed to the loaded script * * @return return value for load call (undefined) * * @throws IOException if source cannot be found or loaded */ - public Object loadWithNewGlobal(final Object from) throws IOException { + public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException { final ScriptObject oldGlobal = getGlobalTrusted(); final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() { @Override @@ -518,6 +527,9 @@ public final class Context { }); setGlobalTrusted(newGlobal); + final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, newGlobal); + newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped)); + try { return ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal); } finally { diff --git a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java index 98b79150..04211fc6 100644 --- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java +++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java @@ -373,11 +373,16 @@ loop: sb.append(ch); } else if (ch < 256) { sb.append('%'); - final byte b = (byte)ch; - sb.append(Integer.toHexString(b & 0xFF).toUpperCase(Locale.ENGLISH)); + if (ch < 16) { + sb.append('0'); + } + sb.append(Integer.toHexString(ch).toUpperCase(Locale.ENGLISH)); } else { sb.append("%u"); - sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase(Locale.ENGLISH)); + if (ch < 4096) { + sb.append('0'); + } + sb.append(Integer.toHexString(ch).toUpperCase(Locale.ENGLISH)); } } diff --git a/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/src/jdk/nashorn/internal/runtime/JSONFunctions.java index c296a87a..2895cb85 100644 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -25,9 +25,6 @@ package jdk.nashorn.internal.runtime; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; - import java.lang.invoke.MethodHandle; import java.util.Iterator; import jdk.nashorn.internal.ir.LiteralNode; @@ -37,6 +34,7 @@ import jdk.nashorn.internal.ir.PropertyNode; import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.parser.JSONParser; import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.arrays.ArrayIndex; import jdk.nashorn.internal.runtime.linker.Bootstrap; /** @@ -66,13 +64,9 @@ public final class JSONFunctions { */ public static Object parse(final Object text, final Object reviver) { final String str = JSType.toString(text); - final Context context = Context.getContextTrusted(); final JSONParser parser = new JSONParser( new Source("<json>", str), - new Context.ThrowErrorManager(), - (context != null) ? - context.getEnv()._strict : - false); + new Context.ThrowErrorManager()); Node node; @@ -107,7 +101,6 @@ public final class JSONFunctions { final Object val = holder.get(name); if (val instanceof ScriptObject) { final ScriptObject valueObj = (ScriptObject)val; - final boolean strict = valueObj.isStrictContext(); final Iterator<String> iter = valueObj.propertyIterator(); while (iter.hasNext()) { @@ -115,9 +108,9 @@ public final class JSONFunctions { final Object newElement = walk(valueObj, key, reviver); if (newElement == ScriptRuntime.UNDEFINED) { - valueObj.delete(key, strict); + valueObj.delete(key, false); } else { - setPropertyValue(valueObj, key, newElement, strict); + setPropertyValue(valueObj, key, newElement, false); } } } @@ -170,14 +163,13 @@ public final class JSONFunctions { } else if (node instanceof ObjectNode) { final ObjectNode objNode = (ObjectNode) node; final ScriptObject object = ((GlobalObject)global).newObject(); - final boolean strict = global.isStrictContext(); for (final PropertyNode pNode: objNode.getElements()) { final Node valueNode = pNode.getValue(); final String name = pNode.getKeyName(); final Object value = convertNode(global, valueNode); - setPropertyValue(object, name, value, strict); + setPropertyValue(object, name, value, false); } return object; @@ -192,8 +184,8 @@ public final class JSONFunctions { // add a new property if does not exist already, or else set old property private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(name); - if (isValidArrayIndex(index)) { + final int index = ArrayIndex.getArrayIndex(name); + if (ArrayIndex.isValidArrayIndex(index)) { // array index key sobj.defineOwnProperty(index, value); } else if (sobj.getMap().findProperty(name) != null) { diff --git a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java index 883ff85c..145afac6 100644 --- a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java +++ b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java @@ -199,7 +199,6 @@ public final class NativeJavaPackage extends ScriptObject { final String fullName = name.isEmpty() ? propertyName : name + "." + propertyName; final Context context = getContext(); - final boolean strict = context._strict; Class<?> javaClass = null; try { @@ -209,9 +208,9 @@ public final class NativeJavaPackage extends ScriptObject { } if (javaClass == null) { - set(propertyName, new NativeJavaPackage(fullName, getProto()), strict); + set(propertyName, new NativeJavaPackage(fullName, getProto()), false); } else { - set(propertyName, StaticClass.forClass(javaClass), strict); + set(propertyName, StaticClass.forClass(javaClass), false); } return super.lookup(desc, request); diff --git a/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java b/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java index a0c2f823..34db0cb3 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java +++ b/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java @@ -61,7 +61,7 @@ public class PropertyListenerManager implements PropertyListener { * * @param listener The property listener that is added. */ - public final void addPropertyListener(final PropertyListener listener) { + public synchronized final void addPropertyListener(final PropertyListener listener) { if (listeners == null) { listeners = new WeakHashMap<>(); } @@ -77,7 +77,7 @@ public class PropertyListenerManager implements PropertyListener { * * @param listener The property listener that is removed. */ - public final void removePropertyListener(final PropertyListener listener) { + public synchronized final void removePropertyListener(final PropertyListener listener) { if (listeners != null) { if (Context.DEBUG) { listenersRemoved++; @@ -92,7 +92,7 @@ public class PropertyListenerManager implements PropertyListener { * @param object The ScriptObject to which property was added. * @param prop The property being added. */ - protected final void notifyPropertyAdded(final ScriptObject object, final Property prop) { + protected synchronized final void notifyPropertyAdded(final ScriptObject object, final Property prop) { if (listeners != null) { for (PropertyListener listener : listeners.keySet()) { listener.propertyAdded(object, prop); @@ -106,7 +106,7 @@ public class PropertyListenerManager implements PropertyListener { * @param object The ScriptObject from which property was deleted. * @param prop The property being deleted. */ - protected final void notifyPropertyDeleted(final ScriptObject object, final Property prop) { + protected synchronized final void notifyPropertyDeleted(final ScriptObject object, final Property prop) { if (listeners != null) { for (PropertyListener listener : listeners.keySet()) { listener.propertyDeleted(object, prop); @@ -121,7 +121,7 @@ public class PropertyListenerManager implements PropertyListener { * @param oldProp The old property being replaced. * @param newProp The new property that replaces the old property. */ - protected final void notifyPropertyModified(final ScriptObject object, final Property oldProp, final Property newProp) { + protected synchronized final void notifyPropertyModified(final ScriptObject object, final Property oldProp, final Property newProp) { if (listeners != null) { for (PropertyListener listener : listeners.keySet()) { listener.propertyModified(object, oldProp, newProp); diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java index 077218d3..b7248166 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -95,7 +95,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener { */ private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) { this.properties = properties; - this.hashCode = computeHashCode(); this.fieldCount = fieldCount; this.fieldMaximum = fieldMaximum; @@ -125,7 +124,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener { this.spillLength = propertyMap.spillLength; this.fieldCount = propertyMap.fieldCount; this.fieldMaximum = propertyMap.fieldMaximum; - this.hashCode = computeHashCode(); if (Context.DEBUG) { count++; @@ -610,6 +608,9 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener { @Override public int hashCode() { + if (hashCode == 0 && !properties.isEmpty()) { + hashCode = computeHashCode(); + } return hashCode; } diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index 2ca897db..f04dedf0 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -56,9 +56,6 @@ public final class ScriptEnvironment { /** Current Options object. */ private final Options options; - /** Always allow functions as statements */ - public final boolean _anon_functions; - /** Size of the per-global Class cache size */ public final int _class_cache_size; @@ -192,7 +189,6 @@ public final class ScriptEnvironment { this.namespace = new Namespace(); this.options = options; - _anon_functions = options.getBoolean("anon.functions"); _class_cache_size = options.getInteger("class.cache.size"); _compile_only = options.getBoolean("compile.only"); _debug_lines = options.getBoolean("debug.lines"); diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 331687ad..0a2337f4 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -37,8 +37,6 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET; import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow; -import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -65,6 +63,7 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.objects.AccessorPropertyDescriptor; import jdk.nashorn.internal.objects.DataPropertyDescriptor; import jdk.nashorn.internal.runtime.arrays.ArrayData; +import jdk.nashorn.internal.runtime.arrays.ArrayIndex; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; @@ -106,6 +105,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr /** Is this a prototype PropertyMap? */ public static final int IS_PROTOTYPE = 0b0000_1000; + /** Is length property not-writable? */ + public static final int IS_LENGTH_NOT_WRITABLE = 0b0001_0000; + /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */ public static final int SPILL_RATE = 8; @@ -333,7 +335,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return global.newDataDescriptor(getWithProperty(property), configurable, enumerable, writable); } - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -444,7 +446,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr if (newValue && property != null) { // Temporarily clear flags. property = modifyOwnProperty(property, 0); - set(key, value, getContext()._strict); + set(key, value, false); } if (property == null) { @@ -533,21 +535,23 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * from any object in proto chain such as Array.prototype, Object.prototype. * This method directly sets a particular element value in the current object. * - * @param index index key for property + * @param index key for property * @param value value to define */ protected final void defineOwnProperty(final int index, final Object value) { - if (index >= getArray().length()) { + assert ArrayIndex.isValidArrayIndex(index) : "invalid array index"; + final long longIndex = ArrayIndex.toLongIndex(index); + if (longIndex >= getArray().length()) { // make array big enough to hold.. - setArray(getArray().ensure(index)); + setArray(getArray().ensure(longIndex)); } setArray(getArray().set(index, value, false)); } private void checkIntegerKey(final String key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { @@ -557,7 +561,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private void removeArraySlot(final String key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -997,7 +1001,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @param value the value to write at the given index */ public void setArgument(final int key, final Object value) { - set(key, value, getContext()._strict); + set(key, value, false); } /** @@ -1104,7 +1108,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } /** - * return a List of own keys associated with the object. + * return an array of own property keys associated with the object. + * * @param all True if to include non-enumerable keys. * @return Array of keys. */ @@ -1205,7 +1210,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * the proto chain * * @param instance instace to check - * @return true if instance of instance + * @return true if 'instance' is an instance of this object */ public boolean isInstance(final ScriptObject instance) { return false; @@ -1276,14 +1281,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * * @return {@code true} if is prototype */ - public boolean isPrototype() { + public final boolean isPrototype() { return (flags & IS_PROTOTYPE) != 0; } /** * Flag this object as having a prototype. */ - public void setIsPrototype() { + public final void setIsPrototype() { if (proto != null && !isPrototype()) { proto.addPropertyListener(this); } @@ -1291,6 +1296,22 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } /** + * Check if this object has non-writable length property + * + * @return {@code true} if 'length' property is non-writable + */ + public final boolean isLengthNotWritable() { + return (flags & IS_LENGTH_NOT_WRITABLE) != 0; + } + + /** + * Flag this object as having non-writable length property + */ + public void setIsLengthNotWritable() { + flags |= IS_LENGTH_NOT_WRITABLE; + } + + /** * Get the {@link ArrayData} for this ScriptObject if it is an array * @return array data */ @@ -1362,7 +1383,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr /** * Check whether this ScriptObject is frozen - * @return true if frozed + * @return true if frozen */ public boolean isFrozen() { return getMap().isFrozen(); @@ -1392,7 +1413,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * (java.util.Map-like method to help ScriptObjectMirror implementation) */ public void clear() { - final boolean strict = getContext()._strict; + final boolean strict = isStrictContext(); final Iterator<String> iter = propertyIterator(); while (iter.hasNext()) { delete(iter.next(), strict); @@ -1480,7 +1501,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr */ public Object put(final Object key, final Object value) { final Object oldValue = get(key); - set(key, value, getContext()._strict); + set(key, value, isStrictContext()); return oldValue; } @@ -1492,7 +1513,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @param otherMap a {@literal <key,value>} map of properties to add */ public void putAll(final Map<?, ?> otherMap) { - final boolean strict = getContext()._strict; + final boolean strict = isStrictContext(); for (final Map.Entry<?, ?> entry : otherMap.entrySet()) { set(entry.getKey(), entry.getValue(), strict); } @@ -1507,7 +1528,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr */ public Object remove(final Object key) { final Object oldValue = get(key); - delete(key, getContext()._strict); + delete(key, isStrictContext()); return oldValue; } @@ -1519,7 +1540,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @return if the delete was successful or not */ public boolean delete(final Object key) { - return delete(key, getContext()._strict); + return delete(key, isStrictContext()); } /** @@ -2221,7 +2242,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return; } - final boolean isStrict = getContext()._strict; + final boolean isStrict = isStrictContext(); if (newLength > arrayLength) { setArray(getArray().ensure(newLength - 1)); @@ -2238,7 +2259,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private int getInt(final int index, final String key) { - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { final FindProperty find = object.findProperty(key, false, false, this); @@ -2269,7 +2290,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public int getInt(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2281,7 +2302,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public int getInt(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2293,7 +2314,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public int getInt(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2315,7 +2336,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private long getLong(final int index, final String key) { - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { final FindProperty find = object.findProperty(key, false, false, this); @@ -2346,7 +2367,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public long getLong(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2358,7 +2379,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public long getLong(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2370,7 +2391,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public long getLong(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2392,7 +2413,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private double getDouble(final int index, final String key) { - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { final FindProperty find = object.findProperty(key, false, false, this); @@ -2423,7 +2444,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public double getDouble(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2435,7 +2456,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public double getDouble(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2447,7 +2468,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public double getDouble(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2469,7 +2490,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private Object get(final int index, final String key) { - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { final FindProperty find = object.findProperty(key, false, false, this); @@ -2500,7 +2521,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public Object get(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2512,7 +2533,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public Object get(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2524,7 +2545,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public Object get(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -2640,9 +2661,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final Object key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2657,9 +2678,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final Object key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2674,9 +2695,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final Object key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2691,9 +2712,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final Object key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2711,9 +2732,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final double key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2728,9 +2749,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final double key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2745,9 +2766,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final double key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2762,9 +2783,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final double key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2779,9 +2800,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final long key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2796,9 +2817,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final long key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2813,9 +2834,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final long key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2830,9 +2851,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final long key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2847,9 +2868,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final int key, final int value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2864,9 +2885,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final int key, final long value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2881,9 +2902,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final int key, final double value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2898,9 +2919,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public void set(final int key, final Object value, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { if (getArray().has(index)) { setArray(getArray().set(index, value, strict)); } else { @@ -2915,9 +2936,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean has(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject self = this; self != null; self = self.getProto()) { if (self.getArray().has(index)) { return true; @@ -2932,9 +2953,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean has(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject self = this; self != null; self = self.getProto()) { if (self.getArray().has(index)) { return true; @@ -2949,9 +2970,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean has(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject self = this; self != null; self = self.getProto()) { if (self.getArray().has(index)) { return true; @@ -2966,9 +2987,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean has(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); - if (isValidArrayIndex(index)) { + if (ArrayIndex.isValidArrayIndex(index)) { for (ScriptObject self = this; self != null; self = self.getProto()) { if (self.getArray().has(index)) { return true; @@ -2983,7 +3004,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean hasOwnProperty(final Object key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (getArray().has(index)) { return true; @@ -2996,7 +3017,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean hasOwnProperty(final int key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (getArray().has(index)) { return true; @@ -3009,7 +3030,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean hasOwnProperty(final long key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (getArray().has(index)) { return true; @@ -3022,7 +3043,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean hasOwnProperty(final double key) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); if (getArray().has(index)) { return true; @@ -3035,7 +3056,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean delete(final int key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -3051,7 +3072,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean delete(final long key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -3067,7 +3088,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean delete(final double key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { @@ -3083,7 +3104,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr @Override public boolean delete(final Object key, final boolean strict) { - final int index = getArrayIndexNoThrow(key); + final int index = ArrayIndex.getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index d5ab68b2..f1febc0c 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -825,6 +825,13 @@ public final class ScriptRuntime { return ((StaticClass)clazz).getRepresentedClass().isInstance(obj); } + if (clazz instanceof ScriptObjectMirror) { + if (obj instanceof ScriptObjectMirror) { + return ((ScriptObjectMirror)clazz).isInstance((ScriptObjectMirror)obj); + } + return false; + } + throw typeError("instanceof.on.non.object"); } diff --git a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index ee1639d0..6bd0479f 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -221,10 +221,9 @@ public final class ScriptingFunctions { final String err = errBuffer.toString(); // Set globals for secondary results. - final boolean isStrict = global.isStrictContext(); - global.set(OUT_NAME, out, isStrict); - global.set(ERR_NAME, err, isStrict); - global.set(EXIT_NAME, exit, isStrict); + global.set(OUT_NAME, out, false); + global.set(ERR_NAME, err, false); + global.set(EXIT_NAME, exit, false); // Propagate exception if present. for (int i = 0; i < exception.length; i++) { diff --git a/src/jdk/nashorn/internal/runtime/Source.java b/src/jdk/nashorn/internal/runtime/Source.java index 24c041a8..b5033e95 100644 --- a/src/jdk/nashorn/internal/runtime/Source.java +++ b/src/jdk/nashorn/internal/runtime/Source.java @@ -116,7 +116,20 @@ public final class Source { * @throws IOException if source cannot be loaded */ public Source(final String name, final URL url) throws IOException { - this(name, baseURL(url, null), readFully(url.openStream()), url); + this(name, baseURL(url, null), readFully(url), url); + } + + /** + * Constructor + * + * @param name source name + * @param url url from which source can be loaded + * @param cs Charset used to convert bytes to chars + * + * @throws IOException if source cannot be loaded + */ + public Source(final String name, final URL url, final Charset cs) throws IOException { + this(name, baseURL(url, null), readFully(url, cs), url); } /** @@ -131,6 +144,19 @@ public final class Source { this(name, dirName(file, null), readFully(file), getURLFromFile(file)); } + /** + * Constructor + * + * @param name source name + * @param file file from which source can be loaded + * @param cs Charset used to convert bytes to chars + * + * @throws IOException if source cannot be loaded + */ + public Source(final String name, final File file, final Charset cs) throws IOException { + this(name, dirName(file, null), readFully(file, cs), getURLFromFile(file)); + } + @Override public boolean equals(final Object obj) { if (this == obj) { @@ -344,6 +370,53 @@ public final class Source { } /** + * Read all of the source until end of file. Return it as char array + * + * @param file source file + * @param cs Charset used to convert bytes to chars + * @return source as content + * + * @throws IOException if source could not be read + */ + public static char[] readFully(final File file, final Charset cs) throws IOException { + if (!file.isFile()) { + throw new IOException(file + " is not a file"); //TODO localize? + } + + final byte[] buf = Files.readAllBytes(file.toPath()); + if (cs != null) { + return new String(buf, cs).toCharArray(); + } else { + return byteToCharArray(buf); + } + } + + /** + * Read all of the source until end of stream from the given URL. Return it as char array + * + * @param url URL to read content from + * @return source as content + * + * @throws IOException if source could not be read + */ + public static char[] readFully(final URL url) throws IOException { + return readFully(url.openStream()); + } + + /** + * Read all of the source until end of file. Return it as char array + * + * @param url URL to read content from + * @param cs Charset used to convert bytes to chars + * @return source as content + * + * @throws IOException if source could not be read + */ + public static char[] readFully(final URL url, final Charset cs) throws IOException { + return readFully(url.openStream(), cs); + } + + /** * Get the base url. This is currently used for testing only * @param url a URL * @return base URL for url @@ -391,6 +464,14 @@ public final class Source { return (idx != -1)? name.substring(0, idx + 1) : defaultValue; } + private static char[] readFully(final InputStream is, final Charset cs) throws IOException { + if (cs != null) { + return new String(readBytes(is), cs).toCharArray(); + } else { + return readFully(is); + } + } + private static char[] readFully(final InputStream is) throws IOException { return byteToCharArray(readBytes(is)); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java index 531c56b5..f59229c4 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java @@ -44,7 +44,7 @@ public final class ArrayIndex { /** * Fast conversion of non-negative integer string to long. * @param key Key as a string. - * @return long value of string or -1. + * @return long value of string or {@code -1} if string does not represent a valid index. */ private static long fromString(final String key) { long value = 0; @@ -52,7 +52,7 @@ public final class ArrayIndex { // Check for empty string or leading 0 if (length == 0 || (length > 1 && key.charAt(0) == '0')) { - return -1; + return INVALID_ARRAY_INDEX; } // Fast toNumber. @@ -61,7 +61,7 @@ public final class ArrayIndex { // If not a digit. if (digit < '0' || digit > '9') { - return -1; + return INVALID_ARRAY_INDEX; } // Insert digit. @@ -69,7 +69,7 @@ public final class ArrayIndex { // Check for overflow (need to catch before wrap around.) if (value > MAX_ARRAY_INDEX) { - return -1; + return INVALID_ARRAY_INDEX; } } @@ -81,137 +81,79 @@ public final class ArrayIndex { * routine needs to perform quickly since all keys are tested with it. * * @param key key to check for array index - * @return valid array index, or negative value if not valid + * @return the array index, or {@code -1} if {@code key} does not represent a valid index. + * Note that negative return values other than {@code -1} are considered valid and can be converted to + * the actual index using {@link #toLongIndex(int)}. */ - public static int getArrayIndexNoThrow(final Object key) { + public static int getArrayIndex(final Object key) { if (key instanceof Integer) { - return getArrayIndexNoThrow(((Integer)key).intValue()); + return getArrayIndex(((Integer) key).intValue()); } else if (key instanceof Number) { - return getArrayIndexNoThrow(((Number)key).doubleValue()); + return getArrayIndex(((Number) key).doubleValue()); } else if (key instanceof String) { - return (int)fromString((String)key); + return (int)fromString((String) key); } else if (key instanceof ConsString) { return (int)fromString(key.toString()); } - return -1; + return INVALID_ARRAY_INDEX; } /** - * Returns a valid array index in an int, if the object represents one + * Returns a valid array index in an int, if the long represents one. * * @param key key to check - * @return array index for key - * @throws InvalidArrayIndexException if not a valid array index key + * @return the array index, or {@code -1} if long is not a valid array index. + * Note that negative return values other than {@code -1} are considered valid and can be converted to + * the actual index using {@link #toLongIndex(int)}. */ - public static int getArrayIndex(final Object key) throws InvalidArrayIndexException { - final int index = getArrayIndexNoThrow(key); - if (index != -1) { - return index; - } - - throw new InvalidArrayIndexException(key); - } - - /** - * Returns a valid array index in an int, if the long represents one - * - * @param key key to check - * @return valid index or a negative value if long is not a valid array index - */ - public static int getArrayIndexNoThrow(final long key) { + public static int getArrayIndex(final long key) { if (key >= 0 && key <= MAX_ARRAY_INDEX) { return (int)key; } - return -1; - } - - /** - * Returns a valid array index in an int, if the long represents one - * - * @param key key to check - * @return valid index for the long - * @throws InvalidArrayIndexException if long is not a valid array index - */ - public static int getArrayIndex(final long key) throws InvalidArrayIndexException { - final int index = getArrayIndexNoThrow(key); - if (index != -1) { - return index; - } - - throw new InvalidArrayIndexException(key); + return INVALID_ARRAY_INDEX; } /** - * Return a valid index for this double, if it represents one + * Return a valid index for this double, if it represents one. * * Doubles that aren't representable exactly as longs/ints aren't working * array indexes, however, array[1.1] === array["1.1"] in JavaScript. * * @param key the key to check - * @return the array index this double represents or a negative value if this isn't an index + * @return the array index this double represents or {@code -1} if this isn't a valid index. + * Note that negative return values other than {@code -1} are considered valid and can be converted to + * the actual index using {@link #toLongIndex(int)}. */ - public static int getArrayIndexNoThrow(final double key) { + public static int getArrayIndex(final double key) { if (JSType.isRepresentableAsInt(key)) { final int intKey = (int)key; if (intKey >= 0) { return intKey; } } else if (JSType.isRepresentableAsLong(key)) { - return getArrayIndexNoThrow((long)key); + return getArrayIndex((long) key); } - return -1; + return INVALID_ARRAY_INDEX; } - /** - * Return a valid array index for this double, if it represents one - * - * Doubles that aren't representable exactly as longs/ints aren't working - * array indexes, however, array[1.1] === array["1.1"] in JavaScript. - * - * @param key the key to check - * @return the array index this double represents - * @throws InvalidArrayIndexException if this isn't an array index - */ - public static int getArrayIndex(final double key) throws InvalidArrayIndexException { - final int index = getArrayIndexNoThrow(key); - if (index != -1) { - return index; - } - - throw new InvalidArrayIndexException(key); - } /** - * Return a valid array index for this string, if it represents one + * Return a valid array index for this string, if it represents one. * * @param key the key to check - * @return the array index this string represents or a negative value if this isn't an index + * @return the array index this string represents or {@code -1} if this isn't a valid index. + * Note that negative return values other than {@code -1} are considered valid and can be converted to + * the actual index using {@link #toLongIndex(int)}. */ - public static int getArrayIndexNoThrow(final String key) { + public static int getArrayIndex(final String key) { return (int)fromString(key); } /** - * Return a valid array index for this string, if it represents one - * - * @param key the key to check - * @return the array index this string represents - * @throws InvalidArrayIndexException if the string isn't an array index - */ - public static int getArrayIndex(final String key) throws InvalidArrayIndexException { - final int index = getArrayIndexNoThrow(key); - if (index != -1) { - return index; - } - - throw new InvalidArrayIndexException(key); - } - - /** * Check whether an index is valid as an array index. This check only tests if * it is the special "invalid array index" type, not if it is e.g. less than zero * or corrupt in some other way @@ -226,7 +168,7 @@ public final class ArrayIndex { /** * Convert an index to a long value. This basically amounts to ANDing it * with {@link JSType#MAX_UINT}, as the maximum array index in JavaScript - * is 0xffffffff + * is 0xfffffffe * * @param index index to convert to long form * @return index as uint32 in a long @@ -236,14 +178,14 @@ public final class ArrayIndex { } /** - * Check whether a key string can be used as a valid numeric array index in - * JavaScript + * Check whether a key string represents a valid array index in JavaScript and is small enough + * to fit into a positive int. * * @param key the key - * @return true if key works as a valid numeric array index + * @return true if key works as a valid int array index */ - public static boolean isIndexKey(final String key) { - return ArrayIndex.getArrayIndexNoThrow(key) >= 0; + public static boolean isIntArrayIndex(final String key) { + return getArrayIndex(key) >= 0; } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java index e250c748..71d4d152 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java @@ -83,6 +83,6 @@ public class ArrayIterator extends ArrayLikeIterator<Object> { @Override public void remove() { - array.delete(index, array.isStrictContext()); + array.delete(index, false); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java index 48505f44..70f74d8e 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime.arrays; import java.util.Iterator; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; @@ -125,6 +126,10 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> { return new MapIterator((ScriptObject)obj, includeUndefined); } + if (obj instanceof ScriptObjectMirror) { + return new ScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); + } + return new EmptyArrayLikeIterator(); } @@ -146,6 +151,10 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> { return new ReverseMapIterator((ScriptObject)obj, includeUndefined); } + if (obj instanceof ScriptObjectMirror) { + return new ReverseScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); + } + assert !obj.getClass().isArray(); return new EmptyArrayLikeIterator(); diff --git a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java index 7568f41b..91b20e5d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime.arrays; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptRuntime; @@ -96,12 +97,18 @@ public abstract class IteratorAction<T> { * @return result of apply */ public final T apply() { - if (!(callbackfn instanceof ScriptFunction)) { + final boolean strict; + if (callbackfn instanceof ScriptFunction) { + strict = ((ScriptFunction)callbackfn).isStrict(); + } else if (callbackfn instanceof ScriptObjectMirror && + ((ScriptObjectMirror)callbackfn).isFunction()) { + strict = ((ScriptObjectMirror)callbackfn).isStrictFunction(); + } else { throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); } - final ScriptFunction func = ((ScriptFunction)callbackfn); + // for non-strict callback, need to translate undefined thisArg to be global object - thisArg = (thisArg == ScriptRuntime.UNDEFINED && !func.isStrict()) ? Context.getGlobal() : thisArg; + thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg; applyLoopBegin(iter); final boolean reverse = iter.isReverse(); diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectMirrorIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectMirrorIterator.java new file mode 100644 index 00000000..1e3e4000 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectMirrorIterator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.nashorn.internal.runtime.arrays; + +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.internal.runtime.JSType; + +/** + * Reverse iterator over a ScriptObjectMirror + */ +final class ReverseScriptObjectMirrorIterator extends ScriptObjectMirrorIterator { + + ReverseScriptObjectMirrorIterator(final ScriptObjectMirror obj, final boolean includeUndefined) { + super(obj, includeUndefined); + this.index = JSType.toUint32(obj.containsKey("length")? obj.getMember("length") : 0) - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} + diff --git a/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectMirrorIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectMirrorIterator.java new file mode 100644 index 00000000..a7bef158 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectMirrorIterator.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.nashorn.internal.runtime.arrays; + +import java.util.NoSuchElementException; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.internal.runtime.JSType; + +/** + * Iterator over a ScriptObjectMirror + */ +class ScriptObjectMirrorIterator extends ArrayLikeIterator<Object> { + + protected final ScriptObjectMirror obj; + private final long length; + + ScriptObjectMirrorIterator(final ScriptObjectMirror obj, final boolean includeUndefined) { + super(includeUndefined); + this.obj = obj; + this.length = JSType.toUint32(obj.containsKey("length")? obj.getMember("length") : 0); + this.index = 0; + } + + protected boolean indexInArray() { + return index < length; + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + if (length == 0L) { + return false; //return empty string if toUint32(length) == 0 + } + + while (indexInArray()) { + if (obj.containsKey(index) || includeUndefined) { + break; + } + bumpIndex(); + } + + return indexInArray(); + } + + @Override + public Object next() { + if (indexInArray()) { + return obj.get(bumpIndex()); + } + + throw new NoSuchElementException(); + } +} + diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index 04ac661f..fd52f22d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -61,13 +61,15 @@ class SparseArrayData extends ArrayData { @Override public Object[] asObjectArray() { - final Object[] objArray = new Object[Math.min((int) length(), Integer.MAX_VALUE)]; + final int length = (int) Math.min(length(), Integer.MAX_VALUE); + final int underlyingLength = (int) Math.min(length, underlying.length()); + final Object[] objArray = new Object[length]; - for (int i = 0; i < underlying.length(); i++) { + for (int i = 0; i < underlyingLength; i++) { objArray[i] = underlying.getObject(i); } - Arrays.fill(objArray, (int) underlying.length(), objArray.length, ScriptRuntime.UNDEFINED); + Arrays.fill(objArray, underlyingLength, length, ScriptRuntime.UNDEFINED); for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) { final long key = entry.getKey(); diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index b8d9e5e3..f058fa33 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -25,9 +25,11 @@ lexer.error.edit.string.missing.brace=Edit string expression missing closing brace lexer.error.here.missing.end.marker=Here string missing end marker "{0}" lexer.error.missing.close.quote=Missing close quote +lexer.error.missing.space.after.number=Missing space after numeric literal lexer.error.invalid.hex=Invalid hex digit -lexer.error.invalid.octal=Invalid octal digit lexer.error.strict.no.octal=cannot use octal escapes in strict mode +lexer.error.json.invalid.number=Invalid JSON number format +lexer.error.invalid.escape.char=Invalid escape character lexer.error.illegal.identifier.character=Illegal character in identifier parser.error.illegal.continue.stmt=Illegal continue statement @@ -127,6 +129,7 @@ type.error.method.not.constructor=Java method {0} can't be used as a constructor type.error.env.not.object=$ENV must be an Object. type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. range.error.inappropriate.array.length=inappropriate array length: {0} +range.error.inappropriate.array.buffer.length=inappropriate array buffer length: {0} range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20] range.error.invalid.precision=precision argument toPrecision() must be in [1, 21] range.error.invalid.radix=radix argument must be in [2, 36] diff --git a/src/jdk/nashorn/internal/runtime/resources/Options.properties b/src/jdk/nashorn/internal/runtime/resources/Options.properties index 4dd6df6f..4d7be62b 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -59,7 +59,7 @@ nashorn.options.D.key = nashorn.option.D ## is_undocumented - should this option never appear in the online help. defaults to no. ## desc - description of what the option does ## default - default value of the option. e.g. debug.lines is true by default. Not set means option not available by default -## dependency - does this arg imply another arg, e.g. scripting -> anon-functions +## dependency - does this arg imply another arg. ## confict - does this arg conflict with another arg e.g trace && instrument ## value_next_arg - is the opton's value passed as next argument in command line? ## @@ -77,16 +77,9 @@ nashorn.option.xhelp = { \ desc="Print extended help for command line flags." \ } -nashorn.option.anon.functions = { \ - name="--anon-functions", \ - short_name="-af", \ - is_undocumented=true, \ - desc="Always allow functions as statements." \ -} - nashorn.option.class.cache.size ={ \ name="--class-cache-size", \ - short_name="--ccs", \ + short_name="-ccs", \ desc="Size of the Class cache size per global scope.", \ is_undocumented=true, \ type=Integer, \ @@ -201,10 +194,10 @@ nashorn.option.loader.per.compile = { \ nashorn.option.no.syntax.extensions = { \ name="--no-syntax-extensions", \ - short_name="--nse", \ + short_name="-nse", \ is_undocumented=true, \ desc="No non-standard syntax extensions", \ - default=-anon-functions=false \ + default=false \ } nashorn.option.package = { \ @@ -296,8 +289,7 @@ nashorn.option.strict = { \ nashorn.option.scripting = { \ name="-scripting", \ - desc="Enable scripting features.", \ - dependency="--anon-functions=true" \ + desc="Enable scripting features." \ } nashorn.option.specialize.calls = { \ |