diff options
50 files changed, 1151 insertions, 431 deletions
diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 7f4ca755..e28da041 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -50,6 +50,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.arrays.ArrayData; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Mirror object that wraps a given Nashorn Script object. @@ -261,7 +262,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin public void setSlot(final int index, final Object value) { inGlobal(new Callable<Void>() { @Override public Void call() { - sobj.set(index, unwrap(value, global), strict); + sobj.set(index, unwrap(value, global), getCallSiteFlags()); return null; } }); @@ -425,7 +426,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) { final Object value = entry.getValue(); final Object modValue = globalChanged? wrap(value, oldGlobal) : value; - sobj.set(entry.getKey(), unwrap(modValue, global), strict); + sobj.set(entry.getKey(), unwrap(modValue, global), getCallSiteFlags()); } return null; } @@ -756,6 +757,10 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin return (obj == ScriptRuntime.UNDEFINED)? null : obj; } + private int getCallSiteFlags() { + return strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0; + } + // internals only below this. private <V> V inGlobal(final Callable<V> callable) { final Global oldGlobal = Context.getGlobal(); diff --git a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java index 774a0be6..491af86f 100644 --- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java +++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java @@ -231,7 +231,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator<T> { if (symbol != null) { if (hasArguments() && symbol.isParam()) { symbol.setFieldIndex(paramCount++); - } else { + } else if (!isValidArrayIndex(getArrayIndex(tuple.key))) { symbol.setFieldIndex(fieldCount++); } } diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java index 995b29a6..c9580d41 100644 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java @@ -558,7 +558,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{ // of the compilation that the object being iterated over must use strings for property // names (e.g., it is a native JS object or array), then we'll not bother trying to treat // the property names optimistically. - !forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())); + !compiler.useOptimisticTypes() || (!forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression()))); } else { if(init != null) { init.accept(this); @@ -686,6 +686,10 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{ @Override public boolean enterReturnNode(final ReturnNode returnNode) { + if(!reachable) { + return false; + } + final Expression returnExpr = returnNode.getExpression(); final Type returnExprType; if(returnExpr != null) { @@ -701,6 +705,9 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{ @Override public boolean enterSplitNode(final SplitNode splitNode) { + if(!reachable) { + return false; + } // Need to visit inside of split nodes. While it's true that they don't have local variables, we need to visit // breaks, continues, and returns in them. if(topSplit == null) { @@ -950,6 +957,9 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{ @Override public boolean enterVarNode(final VarNode varNode) { + if (!reachable) { + return false; + } final Expression init = varNode.getInit(); if(init != null) { init.accept(this); diff --git a/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/src/jdk/nashorn/internal/objects/ArrayBufferView.java index 445dc19c..93506c37 100644 --- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java +++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java @@ -228,11 +228,11 @@ abstract class ArrayBufferView extends ScriptObject { private static void copyElements(final ArrayBufferView dest, final int length, final ScriptObject source, final int offset) { if (!dest.isFloatArray()) { for (int i = 0, j = offset; i < length; i++, j++) { - dest.set(j, source.getInt(i, INVALID_PROGRAM_POINT), false); + dest.set(j, source.getInt(i, INVALID_PROGRAM_POINT), 0); } } else { for (int i = 0, j = offset; i < length; i++, j++) { - dest.set(j, source.getDouble(i, INVALID_PROGRAM_POINT), false); + dest.set(j, source.getDouble(i, INVALID_PROGRAM_POINT), 0); } } } diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 03a2c9ae..b8ec90fd 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -439,8 +439,8 @@ public final class Global extends ScriptObject implements Scope { // current ScriptContext to use - can be null. private ScriptContext scontext; - // associated Property object for "context" property. - private jdk.nashorn.internal.runtime.Property scontextProperty; + // current ScriptEngine associated - can be null. + private ScriptEngine engine; /** * Set the current script context @@ -448,7 +448,6 @@ public final class Global extends ScriptObject implements Scope { */ public void setScriptContext(final ScriptContext scontext) { this.scontext = scontext; - scontextProperty.setValue(this, this, scontext, false); } // global constants for this global - they can be replaced with MethodHandle.constant until invalidated @@ -581,6 +580,7 @@ public final class Global extends ScriptObject implements Scope { return; } + this.engine = engine; init(engine); } @@ -917,6 +917,13 @@ public final class Global extends ScriptObject implements Scope { } } + switch (nameStr) { + case "context": + return sctxt; + case "engine": + return global.engine; + } + if (self == UNDEFINED) { // scope access and so throw ReferenceError throw referenceError(global, "not.defined", nameStr); @@ -1789,9 +1796,6 @@ public final class Global extends ScriptObject implements Scope { } if (engine != null) { - final int NOT_ENUMERABLE_NOT_CONFIG = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE; - scontextProperty = addOwnProperty("context", NOT_ENUMERABLE_NOT_CONFIG, null); - addOwnProperty("engine", NOT_ENUMERABLE_NOT_CONFIG, engine); // default file name addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); // __noSuchProperty__ hook for ScriptContext search of missing variables @@ -1821,10 +1825,10 @@ public final class Global extends ScriptObject implements Scope { // ECMA 15.11.4.2 Error.prototype.name // Error.prototype.name = "Error"; - errorProto.set(NativeError.NAME, "Error", false); + errorProto.set(NativeError.NAME, "Error", 0); // ECMA 15.11.4.3 Error.prototype.message // Error.prototype.message = ""; - errorProto.set(NativeError.MESSAGE, "", false); + errorProto.set(NativeError.MESSAGE, "", 0); this.builtinEvalError = initErrorSubtype("EvalError", errorProto); this.builtinRangeError = initErrorSubtype("RangeError", errorProto); @@ -1837,8 +1841,8 @@ public final class Global extends ScriptObject implements Scope { private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { final ScriptFunction cons = initConstructor(name, ScriptFunction.class); final ScriptObject prototype = ScriptFunction.getPrototype(cons); - prototype.set(NativeError.NAME, name, false); - prototype.set(NativeError.MESSAGE, "", false); + prototype.set(NativeError.NAME, name, 0); + prototype.set(NativeError.MESSAGE, "", 0); prototype.setInitialProto(errorProto); return cons; } @@ -1898,7 +1902,7 @@ public final class Global extends ScriptObject implements Scope { private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { for (final Field f : scriptEnv.getClass().getFields()) { try { - options.set(f.getName(), f.get(scriptEnv), false); + options.set(f.getName(), f.get(scriptEnv), 0); } catch (final IllegalArgumentException | IllegalAccessException exp) { throw new RuntimeException(exp); } @@ -2042,7 +2046,7 @@ public final class Global extends ScriptObject implements Scope { // <anon-function> builtinFunction.setInitialProto(anon); builtinFunction.setPrototype(anon); - anon.set("constructor", builtinFunction, false); + anon.set("constructor", builtinFunction, 0); anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index 776803b3..163e86a4 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -32,6 +32,7 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -69,6 +70,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.arrays.IteratorAction; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Runtime representation of a JavaScript array. NativeArray only holds numeric @@ -341,7 +343,7 @@ public final class NativeArray extends ScriptObject { if (!newWritable) { // make 'length' property not writable final ScriptObject newDesc = Global.newEmptyInstance(); - newDesc.set(WRITABLE, false, false); + newDesc.set(WRITABLE, false, 0); return super.defineOwnProperty("length", newDesc, false); } @@ -808,7 +810,7 @@ public final class NativeArray extends ScriptObject { final long len = JSType.toUint32(sobj.getLength()); if (len == 0) { - sobj.set("length", 0, true); + sobj.set("length", 0, CALLSITE_STRICT); return ScriptRuntime.UNDEFINED; } @@ -816,7 +818,7 @@ public final class NativeArray extends ScriptObject { final Object element = sobj.get(index); sobj.delete(index, true); - sobj.set("length", index, true); + sobj.set("length", index, CALLSITE_STRICT); return element; } catch (final ClassCastException | NullPointerException e) { @@ -844,9 +846,9 @@ public final class NativeArray extends ScriptObject { long len = JSType.toUint32(sobj.getLength()); for (final Object element : args) { - sobj.set(len++, element, true); + sobj.set(len++, element, CALLSITE_STRICT); } - sobj.set("length", len, true); + sobj.set("length", len, CALLSITE_STRICT); return len; } catch (final ClassCastException | NullPointerException e) { @@ -928,8 +930,8 @@ public final class NativeArray extends ScriptObject { } long len = JSType.toUint32(sobj.getLength()); - sobj.set(len++, arg, true); - sobj.set("length", len, true); + sobj.set(len++, arg, CALLSITE_STRICT); + sobj.set("length", len, CALLSITE_STRICT); return len; } catch (final ClassCastException | NullPointerException e) { throw typeError("not.an.object", ScriptRuntime.safeToString(self)); @@ -957,14 +959,14 @@ public final class NativeArray extends ScriptObject { final boolean upperExists = sobj.has(upper); if (lowerExists && upperExists) { - sobj.set(lower, upperValue, true); - sobj.set(upper, lowerValue, true); + sobj.set(lower, upperValue, CALLSITE_STRICT); + sobj.set(upper, lowerValue, CALLSITE_STRICT); } else if (!lowerExists && upperExists) { - sobj.set(lower, upperValue, true); + sobj.set(lower, upperValue, CALLSITE_STRICT); sobj.delete(upper, true); } else if (lowerExists && !upperExists) { sobj.delete(lower, true); - sobj.set(upper, lowerValue, true); + sobj.set(upper, lowerValue, CALLSITE_STRICT); } } return sobj; @@ -1003,7 +1005,7 @@ public final class NativeArray extends ScriptObject { for (long k = 1; k < len; k++) { final boolean hasCurrent = sobj.has(k); if (hasCurrent) { - sobj.set(k - 1, sobj.get(k), true); + sobj.set(k - 1, sobj.get(k), CALLSITE_STRICT); } else if (hasPrevious) { sobj.delete(k - 1, true); } @@ -1015,7 +1017,7 @@ public final class NativeArray extends ScriptObject { len = 0; } - sobj.set("length", len, true); + sobj.set("length", len, CALLSITE_STRICT); return first; } @@ -1226,7 +1228,7 @@ public final class NativeArray extends ScriptObject { final long to = k + items.length; if (sobj.has(from)) { - sobj.set(to, sobj.get(from), true); + sobj.set(to, sobj.get(from), CALLSITE_STRICT); } else { sobj.delete(to, true); } @@ -1242,7 +1244,7 @@ public final class NativeArray extends ScriptObject { if (sobj.has(from)) { final Object fromValue = sobj.get(from); - sobj.set(to, fromValue, true); + sobj.set(to, fromValue, CALLSITE_STRICT); } else { sobj.delete(to, true); } @@ -1251,11 +1253,11 @@ public final class NativeArray extends ScriptObject { long k = start; for (int i = 0; i < items.length; i++, k++) { - sobj.set(k, items[i], true); + sobj.set(k, items[i], CALLSITE_STRICT); } final long newLength = len - deleteCount + items.length; - sobj.set("length", newLength, true); + sobj.set("length", newLength, CALLSITE_STRICT); return array; } @@ -1295,19 +1297,19 @@ public final class NativeArray extends ScriptObject { if (sobj.has(from)) { final Object fromValue = sobj.get(from); - sobj.set(to, fromValue, true); + sobj.set(to, fromValue, CALLSITE_STRICT); } else { sobj.delete(to, true); } } for (int j = 0; j < items.length; j++) { - sobj.set(j, items[j], true); + sobj.set(j, items[j], CALLSITE_STRICT); } } final long newLength = len + items.length; - sobj.set("length", newLength, true); + sobj.set("length", newLength, CALLSITE_STRICT); return newLength; } diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java index dc6ba044..20dd85e5 100644 --- a/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -42,6 +42,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.events.RuntimeEvent; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Nashorn specific debug utils. This is meant for Nashorn developers. @@ -266,7 +267,7 @@ public final class NativeDebug extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static void setEventQueueCapacity(final Object self, final Object newCapacity) { - ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, true); + ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, NashornCallSiteDescriptor.CALLSITE_STRICT); } /** @@ -355,7 +356,7 @@ public final class NativeDebug extends ScriptObject { if (sobj.has(EVENT_QUEUE)) { q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE); } else { - ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), true); + ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), NashornCallSiteDescriptor.CALLSITE_STRICT); } return q; } diff --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index ab544697..f2b1bef4 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -250,146 +250,146 @@ public final class NativeJSAdapter extends ScriptObject { } @Override - public void set(final Object key, final int value, final boolean strict) { + public void set(final Object key, final int value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final Object key, final long value, final boolean strict) { + public void set(final Object key, final long value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final Object key, final double value, final boolean strict) { + public void set(final Object key, final double value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final Object key, final Object value, final boolean strict) { + public void set(final Object key, final Object value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final double key, final int value, final boolean strict) { + public void set(final double key, final int value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final double key, final long value, final boolean strict) { + public void set(final double key, final long value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final double key, final double value, final boolean strict) { + public void set(final double key, final double value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final double key, final Object value, final boolean strict) { + public void set(final double key, final Object value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final long key, final int value, final boolean strict) { + public void set(final long key, final int value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final long key, final long value, final boolean strict) { + public void set(final long key, final long value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final long key, final double value, final boolean strict) { + public void set(final long key, final double value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final long key, final Object value, final boolean strict) { + public void set(final long key, final Object value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final int key, final int value, final boolean strict) { + public void set(final int key, final int value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final int key, final long value, final boolean strict) { + public void set(final int key, final long value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final int key, final double value, final boolean strict) { + public void set(final int key, final double value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } @Override - public void set(final int key, final Object value, final boolean strict) { + public void set(final int key, final Object value, final int flags) { if (overrides && super.hasOwnProperty(key)) { - super.set(key, value, strict); + super.set(key, value, flags); } else { - callAdaptee(__put__, key, value, strict); + callAdaptee(__put__, key, value, flags); } } diff --git a/src/jdk/nashorn/internal/objects/NativeJSON.java b/src/jdk/nashorn/internal/objects/NativeJSON.java index 2578d39a..7bd8a4a3 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSON.java +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java @@ -191,7 +191,7 @@ public final class NativeJSON extends ScriptObject { state.gap = gap; final ScriptObject wrapper = Global.newEmptyInstance(); - wrapper.set("", value, false); + wrapper.set("", value, 0); return str("", wrapper, state); } diff --git a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index 1443c943..d1aa8cb1 100644 --- a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -146,7 +146,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, false); + set(name, value, 0); return true; } return false; diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index 6f47c3fc..3162e184 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -54,6 +54,7 @@ import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; import static jdk.nashorn.internal.parser.TokenType.TERNARY; import static jdk.nashorn.internal.parser.TokenType.WHILE; +import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -2977,11 +2978,13 @@ loop: * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer * for resuming parsing after skipping a function body. */ - private static class ParserState { + private static class ParserState implements Serializable { private final int position; private final int line; private final int linePosition; + private static final long serialVersionUID = -2382565130754093694L; + ParserState(final int position, final int line, final int linePosition) { this.position = position; this.line = line; diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java index e030354a..44b3c3b0 100644 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -119,7 +119,7 @@ public class AccessorProperty extends Property { * produce different boun method handles wrapping the same access mechanism * depending on callsite */ - private MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; + private transient MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; /** * Create a new accessor property. Factory method used by nasgen generated code. diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java index 8d793203..a736cc36 100644 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -34,51 +34,42 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Iterator; import java.util.Map; +import java.util.ServiceLoader; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Logger; +import jdk.nashorn.internal.runtime.options.Options; /** * A code cache for persistent caching of compiled scripts. */ @Logger(name="codestore") -final class CodeStore implements Loggable { - - private final File dir; - private final int minSize; - private final DebugLogger log; - - // Default minimum size for storing a compiled script class - private final static int DEFAULT_MIN_SIZE = 1000; +public abstract class CodeStore implements Loggable { /** - * Constructor - * @throws IOException + * Permission needed to provide a CodeStore instance via ServiceLoader. */ - public CodeStore(final Context context, final String path) throws IOException { - this(context, path, DEFAULT_MIN_SIZE); - } + public final static String NASHORN_PROVIDE_CODE_STORE = "nashorn.provideCodeStore"; + + private DebugLogger log; /** * Constructor - * @param path directory to store code in - * @param minSize minimum file size for caching scripts - * @throws IOException */ - public CodeStore(final Context context, final String path, final int minSize) throws IOException { - this.dir = checkDirectory(path); - this.minSize = minSize; - this.log = initLogger(context); + protected CodeStore() { } @Override public DebugLogger initLogger(final Context context) { - return context.getLogger(getClass()); + log = context.getLogger(getClass()); + return log; } @Override @@ -86,29 +77,101 @@ final class CodeStore implements Loggable { return log; } - private static File checkDirectory(final String path) throws IOException { + /** + * Returns a new code store instance. + * + * @param context the current context + * @return The instance + * @throws IOException If an error occurs + */ + public static CodeStore newCodeStore(final Context context) throws IOException { + final Class<CodeStore> baseClass = CodeStore.class; try { - return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { - @Override - public File run() throws IOException { - final File dir = new File(path).getAbsoluteFile(); - if (!dir.exists() && !dir.mkdirs()) { - throw new IOException("Could not create directory: " + dir.getPath()); - } else if (!dir.isDirectory()) { - throw new IOException("Not a directory: " + dir.getPath()); - } else if (!dir.canRead() || !dir.canWrite()) { - throw new IOException("Directory not readable or writable: " + dir.getPath()); - } - return dir; - } - }); - } catch (final PrivilegedActionException e) { - throw (IOException) e.getException(); + // security check first + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission(NASHORN_PROVIDE_CODE_STORE)); + } + final ServiceLoader<CodeStore> services = ServiceLoader.load(baseClass); + final Iterator<CodeStore> iterator = services.iterator(); + if (iterator.hasNext()) { + final CodeStore store = iterator.next(); + store.initLogger(context).info("using code store provider ", store.getClass().getCanonicalName()); + return store; + } + } catch (final AccessControlException e) { + context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); } + final CodeStore store = new DirectoryCodeStore(); + store.initLogger(context); + return store; + } + + + /** + * Store a compiled script in the cache. + * + * @param functionKey the function key + * @param source the source + * @param mainClassName the main class name + * @param classBytes a map of class bytes + * @param initializers the function initializers + * @param constants the constants array + * @param compilationId the compilation id + */ + public StoredScript store(final String functionKey, + final Source source, + final String mainClassName, + final Map<String, byte[]> classBytes, + final Map<Integer, FunctionInitializer> initializers, + final Object[] constants, + final int compilationId) { + return store(functionKey, source, storedScriptFor(source, mainClassName, classBytes, initializers, constants, compilationId)); } - private File getCacheFile(final Source source, final String functionKey) { - return new File(dir, source.getDigest() + '-' + functionKey); + /** + * Stores a compiled script. + * + * @param functionKey the function key + * @param source the source + * @param script The compiled script + * @return The compiled script or {@code null} if not stored + */ + public abstract StoredScript store(final String functionKey, + final Source source, + final StoredScript script); + + /** + * Return a compiled script from the cache, or null if it isn't found. + * + * @param source the source + * @param functionKey the function key + * @return the stored script or null + */ + public abstract StoredScript load(final Source source, final String functionKey); + + /** + * Returns a new StoredScript instance. + * + * @param mainClassName the main class name + * @param classBytes a map of class bytes + * @param initializers function initializers + * @param constants the constants array + * @param compilationId the compilation id + * @return The compiled script + */ + public StoredScript storedScriptFor(final Source source, final String mainClassName, + final Map<String, byte[]> classBytes, + final Map<Integer, FunctionInitializer> initializers, + final Object[] constants, final int compilationId) { + for (final Object constant : constants) { + // Make sure all constant data is serializable + if (!(constant instanceof Serializable)) { + getLogger().warning("cannot store ", source, " non serializable constant ", constant); + return null; + } + } + return new StoredScript(compilationId, mainClassName, classBytes, initializers, constants); } /** @@ -129,77 +192,130 @@ final class CodeStore implements Loggable { } /** - * Return a compiled script from the cache, or null if it isn't found. - * - * @param source the source - * @param functionKey the function key - * @return the stored script or null + * A store using a file system directory. */ - public StoredScript loadScript(final Source source, final String functionKey) { - if (source.getLength() < minSize) { - return null; + public static class DirectoryCodeStore extends CodeStore { + + // Default minimum size for storing a compiled script class + private final static int DEFAULT_MIN_SIZE = 1000; + + private final File dir; + private final boolean readOnly; + private final int minSize; + + /** + * Constructor + * + * @throws IOException + */ + public DirectoryCodeStore() throws IOException { + this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE); } - final File file = getCacheFile(source, functionKey); + /** + * Constructor + * + * @param path directory to store code in + * @param minSize minimum file size for caching scripts + * @throws IOException + */ + public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException { + this.dir = checkDirectory(path, readOnly); + this.readOnly = readOnly; + this.minSize = minSize; + } - try { - return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() { - @Override - public StoredScript run() throws IOException, ClassNotFoundException { - if (!file.exists()) { - return null; - } - try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { - final StoredScript storedScript = (StoredScript) in.readObject(); - getLogger().info("loaded ", source, "-", functionKey); - return storedScript; + private static File checkDirectory(final String path, final boolean readOnly) throws IOException { + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { + @Override + public File run() throws IOException { + final File dir = new File(path).getAbsoluteFile(); + if (readOnly) { + if (!dir.exists() || !dir.isDirectory()) { + throw new IOException("Not a directory: " + dir.getPath()); + } else if (!dir.canRead()) { + throw new IOException("Directory not readable: " + dir.getPath()); + } + } else if (!dir.exists() && !dir.mkdirs()) { + throw new IOException("Could not create directory: " + dir.getPath()); + } else if (!dir.isDirectory()) { + throw new IOException("Not a directory: " + dir.getPath()); + } else if (!dir.canRead() || !dir.canWrite()) { + throw new IOException("Directory not readable or writable: " + dir.getPath()); + } + return dir; } - } - }); - } catch (final PrivilegedActionException e) { - getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException()); - return null; + }); + } catch (final PrivilegedActionException e) { + throw (IOException) e.getException(); + } } - } - /** - * Store a compiled script in the cache. - * - * @param functionKey the function key - * @param source the source - * @param mainClassName the main class name - * @param classBytes a map of class bytes - * @param constants the constants array - */ - public void storeScript(final String functionKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes, - final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId) { - if (source.getLength() < minSize) { - return; - } - for (final Object constant : constants) { - // Make sure all constant data is serializable - if (! (constant instanceof Serializable)) { - getLogger().warning("cannot store ", source, " non serializable constant ", constant); - return; + @Override + public StoredScript load(final Source source, final String functionKey) { + if (source.getLength() < minSize) { + return null; + } + + final File file = getCacheFile(source, functionKey); + + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() { + @Override + public StoredScript run() throws IOException, ClassNotFoundException { + if (!file.exists()) { + return null; + } + try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { + final StoredScript storedScript = (StoredScript) in.readObject(); + getLogger().info("loaded ", source, "-", functionKey); + return storedScript; + } + } + }); + } catch (final PrivilegedActionException e) { + getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException()); + return null; } } - final File file = getCacheFile(source, functionKey); - final StoredScript script = new StoredScript(compilationId, mainClassName, classBytes, initializers, constants); + @Override + public StoredScript store(final String functionKey, final Source source, final StoredScript script) { + if (readOnly || script == null || belowThreshold(source)) { + return null; + } - try { - AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { - @Override - public Void run() throws IOException { - try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { - out.writeObject(script); + final File file = getCacheFile(source, functionKey); + + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() { + @Override + public StoredScript run() throws IOException { + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { + out.writeObject(script); + } + getLogger().info("stored ", source, "-", functionKey); + return script; } - getLogger().info("stored ", source, "-", functionKey); - return null; - } - }); - } catch (final PrivilegedActionException e) { - getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException()); + }); + } catch (final PrivilegedActionException e) { + getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException()); + return null; + } + } + + + private File getCacheFile(final Source source, final String functionKey) { + return new File(dir, source.getDigest() + '-' + functionKey); + } + + private boolean belowThreshold(final Source source) { + if (source.getLength() < minSize) { + getLogger().info("below size threshold ", source); + return true; + } + return false; } } } diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index c144d363..aa3306a4 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION; import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; +import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.Source.sourceFor; @@ -200,14 +201,14 @@ public final class Context { final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId) { if (context.codeStore != null) { - context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId); + context.codeStore.store(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId); } } @Override public StoredScript loadScript(final Source source, final String functionKey) { if (context.codeStore != null) { - return context.codeStore.loadScript(source, functionKey); + return context.codeStore.load(source, functionKey); } return null; } @@ -463,8 +464,7 @@ public final class Context { if (env._persistent_cache) { try { - final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"); - codeStore = new CodeStore(this, cacheDir); + codeStore = newCodeStore(this); } catch (final IOException e) { throw new RuntimeException("Error initializing code cache", e); } @@ -1117,7 +1117,7 @@ public final class Context { final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null; if (useCodeStore) { - storedScript = codeStore.loadScript(source, cacheKey); + storedScript = codeStore.load(source, cacheKey); } if (storedScript == null) { @@ -1194,15 +1194,16 @@ public final class Context { private static Class<?> install(final StoredScript storedScript, final Source source, final CodeInstaller<ScriptEnvironment> installer) { final Map<String, Class<?>> installedClasses = new HashMap<>(); + final Map<String, byte[]> classBytes = storedScript.getClassBytes(); final Object[] constants = storedScript.getConstants(); final String mainClassName = storedScript.getMainClassName(); - final byte[] mainClassBytes = storedScript.getClassBytes().get(mainClassName); + final byte[] mainClassBytes = classBytes.get(mainClassName); final Class<?> mainClass = installer.install(mainClassName, mainClassBytes); final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers(); installedClasses.put(mainClassName, mainClass); - for (final Map.Entry<String, byte[]> entry : storedScript.getClassBytes().entrySet()) { + for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) { final String className = entry.getKey(); if (className.equals(mainClassName)) { continue; diff --git a/src/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java b/src/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java index c1ae1f59..e69eda92 100644 --- a/src/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java +++ b/src/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java @@ -112,82 +112,82 @@ public abstract class DefaultPropertyAccess implements PropertyAccess { } @Override - public void set(final double key, final int value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final double key, final int value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final double key, final long value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final double key, final long value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final double key, final double value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final double key, final double value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final double key, final Object value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final double key, final Object value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final long key, final int value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final long key, final int value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final long key, final long value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final long key, final long value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final long key, final double value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final long key, final double value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final long key, final Object value, final boolean strict) { - set(JSType.toObject(key), value, strict); + public void set(final long key, final Object value, final int flags) { + set(JSType.toObject(key), value, flags); } @Override - public void set(final int key, final int value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final int key, final int value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final int key, final long value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final int key, final long value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final int key, final double value, final boolean strict) { - set(JSType.toObject(key), JSType.toObject(value), strict); + public void set(final int key, final double value, final int flags) { + set(JSType.toObject(key), JSType.toObject(value), flags); } @Override - public void set(final int key, final Object value, final boolean strict) { - set(JSType.toObject(key), value, strict); + public void set(final int key, final Object value, final int flags) { + set(JSType.toObject(key), value, flags); } @Override - public void set(final Object key, final int value, final boolean strict) { - set(key, JSType.toObject(value), strict); + public void set(final Object key, final int value, final int flags) { + set(key, JSType.toObject(value), flags); } @Override - public void set(final Object key, final long value, final boolean strict) { - set(key, JSType.toObject(value), strict); + public void set(final Object key, final long value, final int flags) { + set(key, JSType.toObject(value), flags); } @Override - public void set(final Object key, final double value, final boolean strict) { - set(key, JSType.toObject(value), strict); + public void set(final Object key, final double value, final int flags) { + set(key, JSType.toObject(value), flags); } @Override - public abstract void set(Object key, Object value, boolean strict); + public abstract void set(Object key, Object value, int flags); @Override public abstract boolean has(Object key); diff --git a/src/jdk/nashorn/internal/runtime/ECMAException.java b/src/jdk/nashorn/internal/runtime/ECMAException.java index ce691afa..954a1707 100644 --- a/src/jdk/nashorn/internal/runtime/ECMAException.java +++ b/src/jdk/nashorn/internal/runtime/ECMAException.java @@ -285,7 +285,7 @@ public final class ECMAException extends NashornException { if (!sobj.has(EXCEPTION_PROPERTY)) { sobj.addOwnProperty(EXCEPTION_PROPERTY, Property.NOT_ENUMERABLE, this); } else { - sobj.set(EXCEPTION_PROPERTY, this, false); + sobj.set(EXCEPTION_PROPERTY, this, 0); } } } diff --git a/src/jdk/nashorn/internal/runtime/FindProperty.java b/src/jdk/nashorn/internal/runtime/FindProperty.java index 72a2d835..06f682bf 100644 --- a/src/jdk/nashorn/internal/runtime/FindProperty.java +++ b/src/jdk/nashorn/internal/runtime/FindProperty.java @@ -139,6 +139,17 @@ public final class FindProperty { } /** + * Return the {@code ScriptObject} where the search started. This is usually the ScriptObject the + * operation was started on, except for properties found inside a 'with' statement, where it is the + * top-level 'with' expression object. + * + * @return the start object. + */ + public ScriptObject getSelf() { + return self; + } + + /** * Return the appropriate receiver for a getter. * @return appropriate receiver */ diff --git a/src/jdk/nashorn/internal/runtime/FunctionInitializer.java b/src/jdk/nashorn/internal/runtime/FunctionInitializer.java index e2912a25..906024d7 100644 --- a/src/jdk/nashorn/internal/runtime/FunctionInitializer.java +++ b/src/jdk/nashorn/internal/runtime/FunctionInitializer.java @@ -60,6 +60,17 @@ public final class FunctionInitializer implements Serializable { } /** + * Copy constructor. + * + * @param init original initializer + */ + FunctionInitializer(final FunctionInitializer init) { + this.className = init.getClassName(); + this.methodType = init.getMethodType(); + this.flags = init.getFlags(); + } + + /** * Constructor. * * @param functionNode the function node diff --git a/src/jdk/nashorn/internal/runtime/GlobalConstants.java b/src/jdk/nashorn/internal/runtime/GlobalConstants.java index df947cdb..3a104812 100644 --- a/src/jdk/nashorn/internal/runtime/GlobalConstants.java +++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java @@ -309,7 +309,7 @@ public final class GlobalConstants implements Loggable { * * @param find property lookup * @param inv normal guarded invocation for this setter, as computed by the ScriptObject linker - * @param desc callsite descriptr + * @param desc callsite descriptor * @param request link request * * @return null if failed to set up constant linkage @@ -376,8 +376,12 @@ public final class GlobalConstants implements Loggable { * @return resulting getter, or null if failed to create constant */ synchronized GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) { - // Also return null if property may have side effects - if ((GLOBAL_ONLY && !find.getOwner().isGlobal()) || find.getProperty() instanceof UserAccessorProperty) { + // Only use constant getter for fast scope access, because the receiver may change between invocations + // for slow-scope and non-scope callsites. + // Also return null for user accessor properties as they may have side effects. + if (!NashornCallSiteDescriptor.isFastScope(desc) + || (GLOBAL_ONLY && !find.getOwner().isGlobal()) + || find.getProperty() instanceof UserAccessorProperty) { return null; } diff --git a/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 5fe57725..a400bbd9 100644 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -122,7 +122,7 @@ public final class JSONFunctions { if (newElement == ScriptRuntime.UNDEFINED) { valueObj.delete(key, false); } else { - setPropertyValue(valueObj, key, newElement, false); + setPropertyValue(valueObj, key, newElement); } } } @@ -179,7 +179,7 @@ public final class JSONFunctions { final String name = pNode.getKeyName(); final Object value = convertNode(global, valueNode); - setPropertyValue(object, name, value, false); + setPropertyValue(object, name, value); } return object; @@ -193,14 +193,14 @@ 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) { + private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value) { final int index = ArrayIndex.getArrayIndex(name); if (ArrayIndex.isValidArrayIndex(index)) { // array index key sobj.defineOwnProperty(index, value); } else if (sobj.getMap().findProperty(name) != null) { // pre-existing non-inherited property, call set - sobj.set(name, value, strict); + sobj.set(name, value, 0); } else { // add new property sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value); diff --git a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java index 27c9bca7..2d110e08 100644 --- a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java +++ b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java @@ -256,7 +256,7 @@ public final class NativeJavaPackage extends ScriptObject { final Object constructor = BeansLinker.getConstructorMethod( javaClass, propertyName.substring(openBrace + 1, lastChar)); if (constructor != null) { - set(propertyName, constructor, false); + set(propertyName, constructor, 0); return constructor; } // we didn't find a matching constructor! @@ -270,7 +270,7 @@ public final class NativeJavaPackage extends ScriptObject { propertyValue = StaticClass.forClass(javaClass); } - set(propertyName, propertyValue, false); + set(propertyName, propertyValue, 0); return propertyValue; } } diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java index c83c4531..1f9f1459 100644 --- a/src/jdk/nashorn/internal/runtime/Property.java +++ b/src/jdk/nashorn/internal/runtime/Property.java @@ -101,7 +101,7 @@ public abstract class Property implements Serializable { private final int slot; /** SwitchPoint that is invalidated when property is changed, optional */ - protected SwitchPoint changeCallback; + protected transient SwitchPoint changeCallback; private static final long serialVersionUID = 2099814273074501176L; diff --git a/src/jdk/nashorn/internal/runtime/PropertyAccess.java b/src/jdk/nashorn/internal/runtime/PropertyAccess.java index 6f09e997..420ef44f 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyAccess.java +++ b/src/jdk/nashorn/internal/runtime/PropertyAccess.java @@ -163,129 +163,129 @@ public interface PropertyAccess { * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(Object key, int value, boolean strict); + public void set(Object key, int value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(Object key, long value, boolean strict); + public void set(Object key, long value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(Object key, double value, boolean strict); + public void set(Object key, double value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(Object key, Object value, boolean strict); + public void set(Object key, Object value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(double key, int value, boolean strict); + public void set(double key, int value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(double key, long value, boolean strict); + public void set(double key, long value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(double key, double value, boolean strict); + public void set(double key, double value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(double key, Object value, boolean strict); + public void set(double key, Object value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(long key, int value, boolean strict); + public void set(long key, int value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(long key, long value, boolean strict); + public void set(long key, long value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(long key, double value, boolean strict); + public void set(long key, double value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(long key, Object value, boolean strict); + public void set(long key, Object value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(int key, int value, boolean strict); + public void set(int key, int value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(int key, long value, boolean strict); + public void set(int key, long value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(int key, double value, boolean strict); + public void set(int key, double value, int flags); /** * Set the value of a given key * @param key the key * @param value the value - * @param strict are we in strict mode + * @param flags call site flags */ - public void set(int key, Object value, boolean strict); + public void set(int key, Object value, int flags); /** * Check if the given key exists anywhere in the proto chain diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java index 0246b531..d8e76082 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -568,9 +568,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable { for (final Property property : otherProperties) { // This method is only safe to use with non-slotted, native getter/setter properties assert property.getSlot() == -1; - if (isValidArrayIndex(getArrayIndex(property.getKey()))) { - newMap.setContainsArrayKeys(); - } + assert !(isValidArrayIndex(getArrayIndex(property.getKey()))); } return newMap; diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 5f5229ba..2d5ccc05 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -491,14 +491,15 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp private FunctionInitializer install(final StoredScript script) { final Map<String, Class<?>> installedClasses = new HashMap<>(); + final Map<String, byte[]> classBytes = script.getClassBytes(); final String mainClassName = script.getMainClassName(); - final byte[] mainClassBytes = script.getClassBytes().get(mainClassName); + final byte[] mainClassBytes = classBytes.get(mainClassName); final Class<?> mainClass = installer.install(mainClassName, mainClassBytes); installedClasses.put(mainClassName, mainClass); - for (final Map.Entry<String, byte[]> entry : script.getClassBytes().entrySet()) { + for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) { final String className = entry.getKey(); final byte[] code = entry.getValue(); diff --git a/src/jdk/nashorn/internal/runtime/RewriteException.java b/src/jdk/nashorn/internal/runtime/RewriteException.java index 37d65f2f..4c0e0a3a 100644 --- a/src/jdk/nashorn/internal/runtime/RewriteException.java +++ b/src/jdk/nashorn/internal/runtime/RewriteException.java @@ -45,6 +45,7 @@ import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.lookup.MethodHandleFunctionality; import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Used to signal to the linker to relink the callee @@ -161,7 +162,7 @@ public final class RewriteException extends Exception { assert runtimeScope == null; runtimeScope = (ScriptObject)value; } else if(name != null) { - locals.set(name, value, true); + locals.set(name, value, NashornCallSiteDescriptor.CALLSITE_STRICT); } } locals.setProto(runtimeScope); diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index cabd1357..8d616b58 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -198,10 +198,10 @@ public abstract class ScriptObject implements PropertyAccess { public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); static final MethodHandle[] SET_SLOW = new MethodHandle[] { - findOwnMH_V("set", void.class, Object.class, int.class, boolean.class), - findOwnMH_V("set", void.class, Object.class, long.class, boolean.class), - findOwnMH_V("set", void.class, Object.class, double.class, boolean.class), - findOwnMH_V("set", void.class, Object.class, Object.class, boolean.class) + findOwnMH_V("set", void.class, Object.class, int.class, int.class), + findOwnMH_V("set", void.class, Object.class, long.class, int.class), + findOwnMH_V("set", void.class, Object.class, double.class, int.class), + findOwnMH_V("set", void.class, Object.class, Object.class, int.class) }; /** Method handle to reset the map of this ScriptObject */ @@ -593,7 +593,7 @@ public abstract class ScriptObject implements PropertyAccess { if (newValue && property != null) { // Temporarily clear flags. property = modifyOwnProperty(property, 0); - set(key, value, false); + set(key, value, 0); //this might change the map if we change types of the property //hence we need to read it again. note that we should probably //have the setter return the new property throughout and in @@ -758,7 +758,7 @@ public abstract class ScriptObject implements PropertyAccess { * @return FindPropertyData or null if not found. */ public final FindProperty findProperty(final String key, final boolean deep) { - return findProperty(key, deep, false, this); + return findProperty(key, deep, this); } /** @@ -775,16 +775,11 @@ public abstract class ScriptObject implements PropertyAccess { * * @param key Property key. * @param deep Whether the search should look up proto chain. - * @param stopOnNonScope should a deep search stop on the first non-scope object? * @param start the object on which the lookup was originally initiated * * @return FindPropertyData or null if not found. */ - FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) { - // if doing deep search, stop search on the first non-scope object if asked to do so - if (stopOnNonScope && start != this && !isScope()) { - return null; - } + FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) { final PropertyMap selfMap = getMap(); final Property property = selfMap.findProperty(key); @@ -796,7 +791,7 @@ public abstract class ScriptObject implements PropertyAccess { if (deep) { final ScriptObject myProto = getProto(); if (myProto != null) { - return myProto.findProperty(key, deep, stopOnNonScope, start); + return myProto.findProperty(key, deep, start); } } @@ -1164,7 +1159,7 @@ public abstract class ScriptObject implements PropertyAccess { * @param value the value to write at the given index */ public void setArgument(final int key, final Object value) { - set(key, value, false); + set(key, value, 0); } /** @@ -1725,7 +1720,8 @@ public abstract class ScriptObject implements PropertyAccess { */ public Object put(final Object key, final Object value, final boolean strict) { final Object oldValue = get(key); - set(key, value, strict); + final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0; + set(key, value, flags); return oldValue; } @@ -1738,8 +1734,9 @@ public abstract class ScriptObject implements PropertyAccess { * @param strict strict mode or not */ public void putAll(final Map<?, ?> otherMap, final boolean strict) { + final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0; for (final Map.Entry<?, ?> entry : otherMap.entrySet()) { - set(entry.getKey(), entry.getValue(), strict); + set(entry.getKey(), entry.getValue(), flags); } } @@ -2042,7 +2039,7 @@ public abstract class ScriptObject implements PropertyAccess { final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION)); setMap(newMap); - set(key, value, true); + set(key, value, 0); } /** @@ -2135,7 +2132,6 @@ public abstract class ScriptObject implements PropertyAccess { return findMegaMorphicSetMethod(desc, name); } - final boolean scope = isScope(); final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request); /* @@ -2145,16 +2141,18 @@ public abstract class ScriptObject implements PropertyAccess { * * toString = function() { print("global toString"); } // don't affect Object.prototype.toString */ - FindProperty find = findProperty(name, true, scope, this); + FindProperty find = findProperty(name, true, this); // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors. - if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { + if (find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { // We should still check if inherited data property is not writable if (isExtensible() && !find.getProperty().isWritable()) { - return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", false); + return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true); + } + // Otherwise, forget the found property unless this is a scope callsite and the owner is a scope object as well. + if (!NashornCallSiteDescriptor.isScope(desc) || !find.getOwner().isScope()) { + find = null; } - // Otherwise, forget the found property - find = null; } if (find != null) { @@ -2180,8 +2178,8 @@ public abstract class ScriptObject implements PropertyAccess { private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); - if (NashornCallSiteDescriptor.isStrict(desc)) { - throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString(this)); + if (NashornCallSiteDescriptor.isStrict(desc)) { + throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString(this)); } assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc); return new GuardedInvocation( @@ -2207,7 +2205,7 @@ public abstract class ScriptObject implements PropertyAccess { private GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) { final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class); //never bother with ClassCastExceptionGuard for megamorphic callsites - final GuardedInvocation inv = findSetIndexMethod(getClass(), false, type, NashornCallSiteDescriptor.isStrict(desc)); + final GuardedInvocation inv = findSetIndexMethod(getClass(), desc, false, type); return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard()); } @@ -2230,24 +2228,26 @@ public abstract class ScriptObject implements PropertyAccess { * @return GuardedInvocation to be invoked at call site. */ protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value - return findSetIndexMethod(getClass(), explicitInstanceOfCheck(desc, request), desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc)); + return findSetIndexMethod(getClass(), desc, explicitInstanceOfCheck(desc, request), desc.getMethodType()); } /** * Find the appropriate SETINDEX method for an invoke dynamic call. * + * @param clazz the receiver class + * @param desc the call site descriptor + * @param explicitInstanceOfCheck add an explicit instanceof check? * @param callType the method type at the call site - * @param isStrict are we in strict mode? * * @return GuardedInvocation to be invoked at call site. */ - private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final boolean explicitInstanceOfCheck, final MethodType callType, final boolean isStrict) { + private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final MethodType callType) { assert callType.parameterCount() == 3; final Class<?> keyClass = callType.parameterType(1); final Class<?> valueClass = callType.parameterType(2); - MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, boolean.class); - methodHandle = MH.insertArguments(methodHandle, 3, isStrict); + MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, int.class); + methodHandle = MH.insertArguments(methodHandle, 3, NashornCallSiteDescriptor.getFlags(desc)); return new GuardedInvocation(methodHandle, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class); } @@ -2672,7 +2672,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { if (object.getMap().containsArrayKeys()) { - final FindProperty find = object.findProperty(key, false, false, this); + final FindProperty find = object.findProperty(key, false, this); if (find != null) { return getIntValue(find, programPoint); @@ -2755,7 +2755,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { if (object.getMap().containsArrayKeys()) { - final FindProperty find = object.findProperty(key, false, false, this); + final FindProperty find = object.findProperty(key, false, this); if (find != null) { return getLongValue(find, programPoint); } @@ -2837,7 +2837,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { if (object.getMap().containsArrayKeys()) { - final FindProperty find = object.findProperty(key, false, false, this); + final FindProperty find = object.findProperty(key, false, this); if (find != null) { return getDoubleValue(find, programPoint); } @@ -2919,7 +2919,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { for (ScriptObject object = this; ; ) { if (object.getMap().containsArrayKeys()) { - final FindProperty find = object.findProperty(key, false, false, this); + final FindProperty find = object.findProperty(key, false, this); if (find != null) { return find.getObjectValue(); @@ -2996,48 +2996,48 @@ public abstract class ScriptObject implements PropertyAccess { return get(index, JSType.toString(key)); } - private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final boolean strict) { + private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) { if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { - setObject(find, strict, key, value); + setObject(find, callSiteFlags, key, value); return true; } } return false; } - private boolean doesNotHaveCheckArrayKeys(final long longIndex, final long value, final boolean strict) { + private boolean doesNotHaveCheckArrayKeys(final long longIndex, final long value, final int callSiteFlags) { if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { - setObject(find, strict, key, value); + setObject(find, callSiteFlags, key, value); return true; } } return false; } - private boolean doesNotHaveCheckArrayKeys(final long longIndex, final double value, final boolean strict) { + private boolean doesNotHaveCheckArrayKeys(final long longIndex, final double value, final int callSiteFlags) { if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { - setObject(find, strict, key, value); + setObject(find, callSiteFlags, key, value); return true; } } return false; } - private boolean doesNotHaveCheckArrayKeys(final long longIndex, final Object value, final boolean strict) { + private boolean doesNotHaveCheckArrayKeys(final long longIndex, final Object value, final int callSiteFlags) { if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { - setObject(find, strict, key, value); + setObject(find, callSiteFlags, key, value); return true; } } @@ -3045,10 +3045,10 @@ public abstract class ScriptObject implements PropertyAccess { } //value agnostic - private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final boolean strict) { + private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) { if (longIndex >= oldLength) { if (!isExtensible()) { - if (strict) { + if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this)); } return true; @@ -3068,37 +3068,41 @@ public abstract class ScriptObject implements PropertyAccess { } } - private void doesNotHave(final int index, final int value, final boolean strict) { + private void doesNotHave(final int index, final int value, final int callSiteFlags) { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (!doesNotHaveCheckArrayKeys(longIndex, value, strict) && !doesNotHaveEnsureLength(longIndex, oldLength, strict)) { + if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { + final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } } - private void doesNotHave(final int index, final long value, final boolean strict) { + private void doesNotHave(final int index, final long value, final int callSiteFlags) { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (!doesNotHaveCheckArrayKeys(longIndex, value, strict) && !doesNotHaveEnsureLength(longIndex, oldLength, strict)) { + if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { + final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } } - private void doesNotHave(final int index, final double value, final boolean strict) { + private void doesNotHave(final int index, final double value, final int callSiteFlags) { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (!doesNotHaveCheckArrayKeys(longIndex, value, strict) && !doesNotHaveEnsureLength(longIndex, oldLength, strict)) { + if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { + final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } } - private void doesNotHave(final int index, final Object value, final boolean strict) { + private void doesNotHave(final int index, final Object value, final int callSiteFlags) { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (!doesNotHaveCheckArrayKeys(longIndex, value, strict) && !doesNotHaveEnsureLength(longIndex, oldLength, strict)) { + if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { + final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3108,32 +3112,47 @@ public abstract class ScriptObject implements PropertyAccess { * This is the most generic of all Object setters. Most of the others use this in some form. * TODO: should be further specialized * - * @param find found property - * @param strict are we in strict mode - * @param key property key - * @param value property value + * @param find found property + * @param callSiteFlags callsite flags + * @param key property key + * @param value property value */ - public final void setObject(final FindProperty find, final boolean strict, final String key, final Object value) { + public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) { FindProperty f = find; - if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty) && !isScope()) { - // Setting a property should not modify the property in prototype unless this is a scope object. - f = null; + if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) { + final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags); + // If the start object of the find is not this object it means the property was found inside a + // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set' + // to the 'with' object. + // Note that although a 'set' operation involving a with statement follows scope rules outside + // the 'with' expression (the 'set' operation is performed on the owning prototype if it exists), + // it follows non-scope rules inside the 'with' expression (set is performed on the top level object). + // This is why we clear the callsite flags and FindProperty in the forward call to the 'with' object. + if (isScope && f.getSelf() != this) { + f.getSelf().setObject(null, 0, key, value); + return; + } + // Setting a property should not modify the property in prototype unless this is a scope callsite + // and the owner is a scope object as well (with the exception of 'with' statement handled above). + if (!isScope || !f.getOwner().isScope()) { + f = null; + } } if (f != null) { if (!f.getProperty().isWritable()) { - if (strict) { + if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this)); } return; } - f.setValue(value, strict); + f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)); } else if (!isExtensible()) { - if (strict) { + if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this)); } } else { @@ -3153,293 +3172,293 @@ public abstract class ScriptObject implements PropertyAccess { } @Override - public void set(final Object key, final int value, final boolean strict) { + public void set(final Object key, final int value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final Object key, final long value, final boolean strict) { + public void set(final Object key, final long value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final Object key, final double value, final boolean strict) { + public void set(final Object key, final double value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final Object key, final Object value, final boolean strict) { + public void set(final Object key, final Object value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); - setObject(findProperty(propName, true), strict, propName, value); + setObject(findProperty(propName, true), callSiteFlags, propName, value); } @Override - public void set(final double key, final int value, final boolean strict) { + public void set(final double key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final double key, final long value, final boolean strict) { + public void set(final double key, final long value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final double key, final double value, final boolean strict) { + public void set(final double key, final double value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final double key, final Object value, final boolean strict) { + public void set(final double key, final Object value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, value); + setObject(findProperty(propName, true), callSiteFlags, propName, value); } @Override - public void set(final long key, final int value, final boolean strict) { + public void set(final long key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final long key, final long value, final boolean strict) { + public void set(final long key, final long value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final long key, final double value, final boolean strict) { + public void set(final long key, final double value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final long key, final Object value, final boolean strict) { + public void set(final long key, final Object value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, value); + setObject(findProperty(propName, true), callSiteFlags, propName, value); } @Override - public void set(final int key, final int value, final boolean strict) { + public void set(final int key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final int key, final long value, final boolean strict) { + public void set(final int key, final long value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final int key, final double value, final boolean strict) { + public void set(final int key, final double value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, JSType.toObject(value)); + setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); } @Override - public void set(final int key, final Object value, final boolean strict) { + public void set(final int key, final Object value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, strict)); + setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { - doesNotHave(index, value, strict); + doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); - setObject(findProperty(propName, true), strict, propName, value); + setObject(findProperty(propName, true), callSiteFlags, propName, value); } @Override diff --git a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index 2113b79c..83583232 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -221,9 +221,9 @@ public final class ScriptingFunctions { final String err = errBuffer.toString(); // Set globals for secondary results. - global.set(OUT_NAME, out, false); - global.set(ERR_NAME, err, false); - global.set(EXIT_NAME, exit, false); + global.set(OUT_NAME, out, 0); + global.set(ERR_NAME, err, 0); + global.set(EXIT_NAME, exit, 0); // Propagate exception if present. for (final IOException element : exception) { diff --git a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java index 757cb305..99ec3135 100644 --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java @@ -205,7 +205,7 @@ final class SetMethodCreator { //slow setter, that calls ScriptObject.set with appropraite type and key name MethodHandle slowSetter = ScriptObject.SET_SLOW[getAccessorTypeIndex(type)]; - slowSetter = MH.insertArguments(slowSetter, 3, NashornCallSiteDescriptor.isStrict(desc)); + slowSetter = MH.insertArguments(slowSetter, 3, NashornCallSiteDescriptor.getFlags(desc)); slowSetter = MH.insertArguments(slowSetter, 1, name); slowSetter = MH.asType(slowSetter, slowSetter.type().changeParameterType(0, Object.class)); diff --git a/src/jdk/nashorn/internal/runtime/StoredScript.java b/src/jdk/nashorn/internal/runtime/StoredScript.java index 7a76b983..5b6a77b2 100644 --- a/src/jdk/nashorn/internal/runtime/StoredScript.java +++ b/src/jdk/nashorn/internal/runtime/StoredScript.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime; import java.io.Serializable; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -83,7 +84,11 @@ public final class StoredScript implements Serializable { * @return map of class bytes */ public Map<String, byte[]> getClassBytes() { - return classBytes; + final Map<String, byte[]> clonedMap = new LinkedHashMap<>(); + for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) { + clonedMap.put(entry.getKey(), entry.getValue().clone()); + } + return clonedMap; } /** @@ -91,11 +96,19 @@ public final class StoredScript implements Serializable { * @return constants array */ public Object[] getConstants() { - return constants; + return constants.clone(); } - Map<Integer, FunctionInitializer> getInitializers() { - return initializers; + /** + * Returns the function initializers map. + * @return The initializers map. + */ + public Map<Integer, FunctionInitializer> getInitializers() { + final Map<Integer, FunctionInitializer> clonedMap = new LinkedHashMap<>(); + for (final Map.Entry<Integer, FunctionInitializer> entry : initializers.entrySet()) { + clonedMap.put(entry.getKey(), new FunctionInitializer(entry.getValue())); + } + return clonedMap; } @Override diff --git a/src/jdk/nashorn/internal/runtime/Undefined.java b/src/jdk/nashorn/internal/runtime/Undefined.java index fc1a028a..57c7e5f1 100644 --- a/src/jdk/nashorn/internal/runtime/Undefined.java +++ b/src/jdk/nashorn/internal/runtime/Undefined.java @@ -34,6 +34,7 @@ import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.internal.dynalink.support.Guards; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Unique instance of this class is used to represent JavaScript undefined. @@ -128,7 +129,7 @@ public final class Undefined extends DefaultPropertyAccess { } private static final MethodHandle GET_METHOD = findOwnMH("get", Object.class, Object.class); - private static final MethodHandle SET_METHOD = MH.insertArguments(findOwnMH("set", void.class, Object.class, Object.class, boolean.class), 3, Boolean.TRUE); + private static final MethodHandle SET_METHOD = MH.insertArguments(findOwnMH("set", void.class, Object.class, Object.class, int.class), 3, NashornCallSiteDescriptor.CALLSITE_STRICT); private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) { return new GuardedInvocation(MH.insertArguments(GET_METHOD, 1, desc.getNameToken(2)), UNDEFINED_GUARD).asType(desc); @@ -152,7 +153,7 @@ public final class Undefined extends DefaultPropertyAccess { } @Override - public void set(final Object key, final Object value, final boolean strict) { + public void set(final Object key, final Object value, final int flags) { throw typeError("cant.set.property.of.undefined", ScriptRuntime.safeToString(key)); } diff --git a/src/jdk/nashorn/internal/runtime/WithObject.java b/src/jdk/nashorn/internal/runtime/WithObject.java index 723b510f..54ec06f5 100644 --- a/src/jdk/nashorn/internal/runtime/WithObject.java +++ b/src/jdk/nashorn/internal/runtime/WithObject.java @@ -193,18 +193,20 @@ public final class WithObject extends ScriptObject implements Scope { * * @param key Property key. * @param deep Whether the search should look up proto chain. - * @param stopOnNonScope should a deep search stop on the first non-scope object? * @param start the object on which the lookup was originally initiated * * @return FindPropertyData or null if not found. */ @Override - FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) { - final FindProperty exprProperty = expression.findProperty(key, deep, stopOnNonScope, start); + FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) { + // We call findProperty on 'expression' with 'expression' itself as start parameter. + // This way in ScriptObject.setObject we can tell the property is from a 'with' expression + // (as opposed from another non-scope object in the proto chain such as Object.prototype). + final FindProperty exprProperty = expression.findProperty(key, true, expression); if (exprProperty != null) { return exprProperty; } - return super.findProperty(key, deep, stopOnNonScope, start); + return super.findProperty(key, deep, start); } @Override diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java index e6b8b90b..f802e039 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java @@ -125,6 +125,15 @@ public class NashornBeansLinker implements GuardingDynamicLinker { @Override public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) { + if (sourceType == ConsString.class) { + if (String.class == targetType1 || CharSequence.class == targetType1) { + return Comparison.TYPE_1_BETTER; + } + + if (String.class == targetType2 || CharSequence.class == targetType2) { + return Comparison.TYPE_2_BETTER; + } + } return linkerServices.compareConversion(sourceType, targetType1, targetType2); } } diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java index f859f7bb..4ed6e3a2 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java @@ -131,11 +131,16 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo } return getInvocation(EMPTY_ELEM_GETTER, self, linkerServices, desc); case "setProp": - case "setElem": + case "setElem": { + final boolean strict = NashornCallSiteDescriptor.isStrict(desc); + if (strict) { + throw typeError("cant.set.property", getArgument(linkRequest), ScriptRuntime.safeToString(self)); + } if (desc.getOperand() != null) { return getInvocation(EMPTY_PROP_SETTER, self, linkerServices, desc); } return getInvocation(EMPTY_ELEM_SETTER, self, linkerServices, desc); + } default: break; } diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java index 1871a2cb..27fc3a2e 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java @@ -255,7 +255,7 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor * @return the Nashorn-specific flags for the call site, or 0 if the passed descriptor is not a Nashorn call site * descriptor. */ - private static int getFlags(final CallSiteDescriptor desc) { + public static int getFlags(final CallSiteDescriptor desc) { return desc instanceof NashornCallSiteDescriptor ? ((NashornCallSiteDescriptor)desc).flags : 0; } @@ -343,6 +343,24 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor } /** + * Returns true if {@code flags} has the {@link #CALLSITE_STRICT} bit set. + * @param flags the flags + * @return true if the flag is set, false otherwise. + */ + public static boolean isStrictFlag(final int flags) { + return (flags & CALLSITE_STRICT) != 0; + } + + /** + * Returns true if {@code flags} has the {@link #CALLSITE_SCOPE} bit set. + * @param flags the flags + * @return true if the flag is set, false otherwise. + */ + public static boolean isScopeFlag(final int flags) { + return (flags & CALLSITE_SCOPE) != 0; + } + + /** * Get a program point from a descriptor (must be optimistic) * @param desc descriptor * @return program point diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 16b4e05d..056dc87d 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -92,7 +92,7 @@ type.error.cant.delete.property.of.undefined=Cannot delete property "{0}" of und # other wrong usages of property type.error.property.has.no.setter=Cannot set property "{0}" of {1} that has only a getter -type.error.cant.set.proto.to.non.object=Cannot set Object {0}'s __proto__ to be a non-object like {1} +type.error.cant.set.proto.to.non.object=Cannot set Object {0}''s __proto__ to be a non-object like {1} type.error.no.such.function={1} has no such function "{0}" type.error.no.such.java.class=No such Java class: {0} type.error.no.such.java.constructor=No such Java constructor: {0} @@ -125,10 +125,10 @@ type.error.prototype.not.an.object="prototype" of {0} is not an Object, it is {1 type.error.cant.load.script=Cannot load script from {0} type.error.JSON.stringify.cyclic=JSON.stringify got a cyclic data structure type.error.cant.convert.string.to.char=Cannot convert string to character; its length must be exactly 1 -type.error.cant.convert.number.to.char=Cannot convert number to character; it's out of 0-65535 range +type.error.cant.convert.number.to.char=Cannot convert number to character; it is out of 0-65535 range type.error.cant.convert.to.java.string=Cannot convert object of type {0} to a Java argument of string type type.error.cant.convert.to.java.number=Cannot convert object of type {0} to a Java argument of number type -type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Can't convert object of type {0}. +type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Cannot convert object of type {0}. type.error.extend.expects.at.least.one.argument=Java.extend needs at least one argument. type.error.extend.expects.at.least.one.type.argument=Java.extend needs at least one type argument. type.error.extend.expects.java.types=Java.extend needs Java types as its arguments. @@ -141,10 +141,10 @@ type.error.extend.ERROR_NO_COMMON_LOADER=Can not find a common class loader for type.error.extend.ERROR_FINAL_FINALIZER=Can not extend class because {0} has a final finalize method. type.error.no.constructor.matches.args=Can not construct {0} with the passed arguments; they do not match any of its constructor signatures. type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. -type.error.method.not.constructor=Java method {0} can't be used as a constructor. +type.error.method.not.constructor=Java method {0} cannot 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}. -type.error.constructor.requires.new=Constructor {0} requires 'new'. +type.error.constructor.requires.new=Constructor {0} requires "new". type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}. range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor diff --git a/test/script/basic/JDK-8043232.js.EXPECTED b/test/script/basic/JDK-8043232.js.EXPECTED index 5fcfab8e..03382ea5 100644 --- a/test/script/basic/JDK-8043232.js.EXPECTED +++ b/test/script/basic/JDK-8043232.js.EXPECTED @@ -6,9 +6,9 @@ TypeError: No such Java constructor: Object(String) TypeError: Java constructor signature invalid: Object()xxxxx TypeError: Java constructor signature invalid: Object( TypeError: Java constructor signature invalid: Object) -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cant be used as a constructor. -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cant be used as a constructor. -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". TypeError: No such Java constructor: Runnable() TypeError: No such Java constructor: Runnable(int) java.lang.InstantiationException: java.io.InputStream diff --git a/test/script/basic/JDK-8047764-strict.js b/test/script/basic/JDK-8047764-strict.js new file mode 100644 index 00000000..d10b5b37 --- /dev/null +++ b/test/script/basic/JDK-8047764-strict.js @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8047764: Indexed or polymorphic set on global affects Object.prototype + * + * @test + * @run + */ + +// Same as JDK-8047764.js but running in strict mode +"use strict"; + +// Test global set operation on properties defined in Object.prototype + +Object.defineProperty(Object.prototype, "prop1", { get: function() { return 1; }, set: function(v) { print("setting prop1: " + v); }}); +Object.defineProperty(Object.prototype, "prop2", { value: 1, writable: false, configurable: false }); + +try { + prop1 = 1; + print("prop 1: " + prop2); +} catch (e) { + print(e.name); +} + +try { + prop2 = 2; + print("prop 2: " + prop2); +} catch (e) { + print(e.name); +} + +// Make sure various ways of setting global toString don't affect Object.prototype.toString + +function checkToString() { + print(global); + print(Object.prototype); + print(global.toString === Object.prototype.toString); + print(objProtoToString === Object.prototype.toString); +} + +var global = this; +var objProtoToString = Object.prototype.toString; +global["toString"] = function() { return "global toString 1"; }; +checkToString(); +global.toString = function() { return "global toString 2"; }; +checkToString(); +toString = function() { return "global toString 3"; }; +checkToString(); diff --git a/test/script/basic/JDK-8047764-strict.js.EXPECTED b/test/script/basic/JDK-8047764-strict.js.EXPECTED new file mode 100644 index 00000000..c452cfac --- /dev/null +++ b/test/script/basic/JDK-8047764-strict.js.EXPECTED @@ -0,0 +1,15 @@ +setting prop1: 1 +prop 1: 1 +TypeError +global toString 1 +[object Object] +false +true +global toString 2 +[object Object] +false +true +global toString 3 +[object Object] +false +true diff --git a/test/script/basic/JDK-8047764.js b/test/script/basic/JDK-8047764.js new file mode 100644 index 00000000..3920323f --- /dev/null +++ b/test/script/basic/JDK-8047764.js @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8047764: Indexed or polymorphic set on global affects Object.prototype + * + * @test + * @run + */ + +// Test global set operation on properties defined in Object.prototype + +Object.defineProperty(Object.prototype, "prop1", { get: function() { return 1; }, set: function(v) { print("setting prop1: " + v); }}); +Object.defineProperty(Object.prototype, "prop2", { value: 1, writable: false, configurable: false }); + +try { + prop1 = 1; + print("prop 1: " + prop2); +} catch (e) { + print(e.name); +} + +try { + prop2 = 2; + print("prop 2: " + prop2); +} catch (e) { + print(e.name); +} + +// Make sure various ways of setting global toString don't affect Object.prototype.toString + +function checkToString() { + print(global); + print(Object.prototype); + print(global.toString === Object.prototype.toString); + print(objProtoToString === Object.prototype.toString); +} + +var global = this; +var objProtoToString = Object.prototype.toString; +global["toString"] = function() { return "global toString 1"; }; +checkToString(); +global.toString = function() { return "global toString 2"; }; +checkToString(); +toString = function() { return "global toString 3"; }; +checkToString(); + +// Test setters on 'with' object + +var p = { prop3: 3, toString: function() { return "[object p]"; }}; +Object.defineProperty(p, "prop4", { get: function() { print("get", this); return 4; }, set: function(v) { print("set", this, v); }}); +var o = Object.create(p); +o.toString = function() { return "[object o]"; }; + +with(o) { + (function() { + var m = 5; + (function() { + print(prop3); + prop3 = m; + print(prop3); + print(prop4); + prop4 = m; + print(prop4); + })(); + })(); +} + +print(o.hasOwnProperty("prop3")); +print(o.prop3); +print(p.prop3); +print(o.hasOwnProperty("prop4")); +print(o.prop4); +print(p.prop4); diff --git a/test/script/basic/JDK-8047764.js.EXPECTED b/test/script/basic/JDK-8047764.js.EXPECTED new file mode 100644 index 00000000..5c9b0eb5 --- /dev/null +++ b/test/script/basic/JDK-8047764.js.EXPECTED @@ -0,0 +1,30 @@ +setting prop1: 1 +prop 1: 1 +prop 2: 1 +global toString 1 +[object Object] +false +true +global toString 2 +[object Object] +false +true +global toString 3 +[object Object] +false +true +3 +5 +get [object o] +4 +set [object o] 5 +get [object o] +4 +true +5 +3 +false +get [object o] +4 +get [object p] +4 diff --git a/test/script/basic/JDK-8049242.js.EXPECTED b/test/script/basic/JDK-8049242.js.EXPECTED index 4aa46276..4a2f4169 100644 --- a/test/script/basic/JDK-8049242.js.EXPECTED +++ b/test/script/basic/JDK-8049242.js.EXPECTED @@ -4,7 +4,7 @@ java.awt.Color[r=33,g=233,b=2] TypeError: null is not a function TypeError: null is not a function TypeError: null is not a function -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". TypeError: null is not a function TypeError: null is not a function java.lang.InstantiationException: java.io.InputStream diff --git a/test/script/basic/JDK-8056978.js b/test/script/basic/JDK-8056978.js new file mode 100644 index 00000000..1b3577d4 --- /dev/null +++ b/test/script/basic/JDK-8056978.js @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8056978: ClassCastException: cannot cast jdk.nashorn.internal.scripts.JO* + * + * @test + * @run + */ + +var obj1 = { + 'name': 'test name', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5' +}; + +var obj2 = { + 'name': 'hello' +}; + +print(obj2['name']); +print(obj2.name); + diff --git a/test/script/basic/JDK-8056978.js.EXPECTED b/test/script/basic/JDK-8056978.js.EXPECTED new file mode 100644 index 00000000..317e9677 --- /dev/null +++ b/test/script/basic/JDK-8056978.js.EXPECTED @@ -0,0 +1,2 @@ +hello +hello diff --git a/test/script/basic/JDK-8058422.js b/test/script/basic/JDK-8058422.js new file mode 100644 index 00000000..b15c7cfb --- /dev/null +++ b/test/script/basic/JDK-8058422.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058422: Users should be able to overwrite "context" and "engine" variables + * + * @test + * @run + */ + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); +e.put("foo", "hello"); +var obj = e.eval("context.getAttribute('foo')"); +if (obj != "hello") { + fail("Expected 'obj' to be 'hello'"); +} + +e.put("context", "bar"); +if (e.eval("context") != "bar") { + fail("Expected 'context' to be 'bar'"); +} + +if (e.eval("foo") != "hello") { + fail("Expected 'foo' to be 'hello'"); +} + +if (e.eval("engine") != e) { + fail("'engine' is not evaluaed to current engine"); +} + +e.put("engine", "foobar"); +if (e.eval("engine") != "foobar") { + fail("'engine' is not evalued to 'foobar'"); +} diff --git a/test/script/basic/JDK-8058545.js b/test/script/basic/JDK-8058545.js new file mode 100644 index 00000000..3b3a7c60 --- /dev/null +++ b/test/script/basic/JDK-8058545.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError + * + * @test + * @run + */ + +'use strict'; +var File = Java.type("java.io.File"); +var f = new File("."); +try { + f.foo = 33; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } +} diff --git a/test/script/basic/JDK-8058561.js b/test/script/basic/JDK-8058561.js new file mode 100644 index 00000000..f27d1d1b --- /dev/null +++ b/test/script/basic/JDK-8058561.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058561: NPE in LocalVariableTypesCalculator + * + * @test + * @run + * @option --lazy-compilation=false + */ + +// Just attempting to compile this caused the NPE +function func(x, y) { + while(true) { + switch (y[0]) { + case "bar": + x = 'xxx'; + break; + } + } + return x; +} diff --git a/test/script/basic/JDK-8058615.js b/test/script/basic/JDK-8058615.js new file mode 100644 index 00000000..354b5e4b --- /dev/null +++ b/test/script/basic/JDK-8058615.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058615: Overload resolution ambiguity involving ConsString + * + * @test + * @run + */ + +var strw = new java.io.StringWriter(); +var bufw = new java.io.BufferedWriter(strw); +var s = "hello "; +bufw.write(s + "world"); +bufw.close(); +print(strw.toString()); diff --git a/test/script/basic/JDK-8058615.js.EXPECTED b/test/script/basic/JDK-8058615.js.EXPECTED new file mode 100644 index 00000000..3b18e512 --- /dev/null +++ b/test/script/basic/JDK-8058615.js.EXPECTED @@ -0,0 +1 @@ +hello world diff --git a/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/test/src/jdk/nashorn/api/scripting/ScopeTest.java index 865c97d6..3e2a6b6e 100644 --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java @@ -582,6 +582,60 @@ public class ScopeTest { assertEquals(e.eval("x", newCtxt), 2); } + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("context", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("context"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("context = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("engine", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("engine"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("engine = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + // @bug 8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook @Test public static void testMegamorphicGetInGlobal() throws Exception { |