Mon, 09 Sep 2013 20:10:41 +0530
8024180: Incorrect handling of expression and parent scope in 'with' statements
Reviewed-by: jlaskey, hannesw
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Sep 05 21:17:06 2013 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Sep 09 20:10:41 2013 +0530 1.3 @@ -315,7 +315,7 @@ 1.4 final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz; 1.5 realSelf = mirror.getScriptObject(); 1.6 realGlobal = mirror.getHomeGlobal(); 1.7 - if (! realGlobal.isOfContext(nashornContext)) { 1.8 + if (! isOfContext(realGlobal, nashornContext)) { 1.9 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 1.10 } 1.11 } else if (thiz instanceof ScriptObject) { 1.12 @@ -326,7 +326,7 @@ 1.13 throw new IllegalArgumentException(getMessage("no.current.nashorn.global")); 1.14 } 1.15 1.16 - if (! realGlobal.isOfContext(nashornContext)) { 1.17 + if (! isOfContext(realGlobal, nashornContext)) { 1.18 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 1.19 } 1.20 } 1.21 @@ -394,7 +394,7 @@ 1.22 // Retrieve nashorn Global object from a given ScriptObjectMirror 1.23 private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) { 1.24 ScriptObject sobj = mirror.getScriptObject(); 1.25 - if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) { 1.26 + if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) { 1.27 return sobj; 1.28 } 1.29 1.30 @@ -470,7 +470,7 @@ 1.31 ScriptObjectMirror selfMirror = null; 1.32 if (selfObject instanceof ScriptObjectMirror) { 1.33 selfMirror = (ScriptObjectMirror)selfObject; 1.34 - if (! selfMirror.getHomeGlobal().isOfContext(nashornContext)) { 1.35 + if (! isOfContext(selfMirror.getHomeGlobal(), nashornContext)) { 1.36 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 1.37 } 1.38 } else if (selfObject instanceof ScriptObject) { 1.39 @@ -481,7 +481,7 @@ 1.40 throw new IllegalArgumentException(getMessage("no.current.nashorn.global")); 1.41 } 1.42 1.43 - if (! oldGlobal.isOfContext(nashornContext)) { 1.44 + if (! isOfContext(oldGlobal, nashornContext)) { 1.45 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 1.46 } 1.47 1.48 @@ -617,4 +617,9 @@ 1.49 } 1.50 return true; 1.51 } 1.52 + 1.53 + private static boolean isOfContext(final ScriptObject global, final Context context) { 1.54 + assert global instanceof GlobalObject: "Not a Global object"; 1.55 + return ((GlobalObject)global).isOfContext(context); 1.56 + } 1.57 }
2.1 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Thu Sep 05 21:17:06 2013 +0530 2.2 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Mon Sep 09 20:10:41 2013 +0530 2.3 @@ -42,6 +42,7 @@ 2.4 import java.util.concurrent.Callable; 2.5 import javax.script.Bindings; 2.6 import jdk.nashorn.internal.runtime.Context; 2.7 +import jdk.nashorn.internal.runtime.GlobalObject; 2.8 import jdk.nashorn.internal.runtime.ScriptFunction; 2.9 import jdk.nashorn.internal.runtime.ScriptObject; 2.10 import jdk.nashorn.internal.runtime.ScriptRuntime; 2.11 @@ -62,6 +63,7 @@ 2.12 2.13 private final ScriptObject sobj; 2.14 private final ScriptObject global; 2.15 + private final boolean strict; 2.16 2.17 @Override 2.18 public boolean equals(final Object other) { 2.19 @@ -101,7 +103,7 @@ 2.20 final Object val = functionName == null? sobj : sobj.get(functionName); 2.21 if (val instanceof ScriptFunction) { 2.22 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; 2.23 - return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); 2.24 + return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); 2.25 } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) { 2.26 return ((ScriptObjectMirror)val).call(null, args); 2.27 } 2.28 @@ -131,7 +133,7 @@ 2.29 final Object val = functionName == null? sobj : sobj.get(functionName); 2.30 if (val instanceof ScriptFunction) { 2.31 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; 2.32 - return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global); 2.33 + return wrap(ScriptRuntime.construct((ScriptFunction)val, unwrapArray(modArgs, global)), global); 2.34 } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) { 2.35 return ((ScriptObjectMirror)val).newObject(null, args); 2.36 } 2.37 @@ -197,7 +199,7 @@ 2.38 public void setSlot(final int index, final Object value) { 2.39 inGlobal(new Callable<Void>() { 2.40 @Override public Void call() { 2.41 - sobj.set(index, unwrap(value, global), global.isStrictContext()); 2.42 + sobj.set(index, unwrap(value, global), strict); 2.43 return null; 2.44 } 2.45 }); 2.46 @@ -209,7 +211,7 @@ 2.47 public void clear() { 2.48 inGlobal(new Callable<Object>() { 2.49 @Override public Object call() { 2.50 - sobj.clear(); 2.51 + sobj.clear(strict); 2.52 return null; 2.53 } 2.54 }); 2.55 @@ -292,7 +294,7 @@ 2.56 return inGlobal(new Callable<Object>() { 2.57 @Override public Object call() { 2.58 final Object modValue = globalChanged? wrap(value, oldGlobal) : value; 2.59 - return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global)); 2.60 + return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global)); 2.61 } 2.62 }); 2.63 } 2.64 @@ -303,7 +305,6 @@ 2.65 final boolean globalChanged = (oldGlobal != global); 2.66 inGlobal(new Callable<Object>() { 2.67 @Override public Object call() { 2.68 - final boolean strict = global.isStrictContext(); 2.69 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) { 2.70 final Object value = entry.getValue(); 2.71 final Object modValue = globalChanged? wrap(value, oldGlobal) : value; 2.72 @@ -318,7 +319,7 @@ 2.73 public Object remove(final Object key) { 2.74 return inGlobal(new Callable<Object>() { 2.75 @Override public Object call() { 2.76 - return wrap(sobj.remove(unwrap(key, global)), global); 2.77 + return wrap(sobj.remove(unwrap(key, global), strict), global); 2.78 } 2.79 }); 2.80 } 2.81 @@ -333,7 +334,7 @@ 2.82 public boolean delete(final Object key) { 2.83 return inGlobal(new Callable<Boolean>() { 2.84 @Override public Boolean call() { 2.85 - return sobj.delete(unwrap(key, global)); 2.86 + return sobj.delete(unwrap(key, global), strict); 2.87 } 2.88 }); 2.89 } 2.90 @@ -637,10 +638,11 @@ 2.91 2.92 ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) { 2.93 assert sobj != null : "ScriptObjectMirror on null!"; 2.94 - assert global != null : "null global for ScriptObjectMirror!"; 2.95 + assert global instanceof GlobalObject : "global is not a GlobalObject"; 2.96 2.97 this.sobj = sobj; 2.98 this.global = global; 2.99 + this.strict = ((GlobalObject)global).isStrictContext(); 2.100 } 2.101 2.102 // accessors for script engine
3.1 --- a/src/jdk/nashorn/internal/objects/Global.java Thu Sep 05 21:17:06 2013 +0530 3.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Mon Sep 09 20:10:41 2013 +0530 3.3 @@ -412,6 +412,14 @@ 3.4 // initialized by nasgen 3.5 private static PropertyMap $nasgenmap$; 3.6 3.7 + // context to which this global belongs to 3.8 + private final Context context; 3.9 + 3.10 + @Override 3.11 + protected Context getContext() { 3.12 + return context; 3.13 + } 3.14 + 3.15 // performs initialization checks for Global constructor and returns the 3.16 // PropertyMap, if everything is fine. 3.17 private static PropertyMap checkAndGetMap(final Context context) { 3.18 @@ -439,7 +447,7 @@ 3.19 */ 3.20 public Global(final Context context) { 3.21 super(checkAndGetMap(context)); 3.22 - this.setContext(context); 3.23 + this.context = context; 3.24 this.setIsScope(); 3.25 3.26 final int cacheSize = context.getEnv()._class_cache_size; 3.27 @@ -482,6 +490,16 @@ 3.28 // GlobalObject interface implementation 3.29 3.30 @Override 3.31 + public boolean isOfContext(final Context context) { 3.32 + return this.context == context; 3.33 + } 3.34 + 3.35 + @Override 3.36 + public boolean isStrictContext() { 3.37 + return context.getEnv()._strict; 3.38 + } 3.39 + 3.40 + @Override 3.41 public void initBuiltinObjects() { 3.42 if (this.builtinObject != null) { 3.43 // already initialized, just return 3.44 @@ -1765,7 +1783,7 @@ 3.45 // do not fill $ENV if we have a security manager around 3.46 // Retrieve current state of ENV variables. 3.47 final ScriptObject env = newObject(); 3.48 - env.putAll(System.getenv()); 3.49 + env.putAll(System.getenv(), scriptEnv._strict); 3.50 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); 3.51 } else { 3.52 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
4.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Thu Sep 05 21:17:06 2013 +0530 4.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Mon Sep 09 20:10:41 2013 +0530 4.3 @@ -573,7 +573,7 @@ 4.4 setGlobalTrusted(newGlobal); 4.5 4.6 final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal); 4.7 - newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped)); 4.8 + newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped), env._strict); 4.9 4.10 try { 4.11 // wrap objects from newGlobal's world as mirrors - but if result
5.1 --- a/src/jdk/nashorn/internal/runtime/GlobalObject.java Thu Sep 05 21:17:06 2013 +0530 5.2 +++ b/src/jdk/nashorn/internal/runtime/GlobalObject.java Mon Sep 09 20:10:41 2013 +0530 5.3 @@ -37,6 +37,18 @@ 5.4 5.5 public interface GlobalObject { 5.6 /** 5.7 + * Is this global of the given Context? 5.8 + * @return true if this global belongs to the given Context 5.9 + */ 5.10 + public boolean isOfContext(Context context); 5.11 + 5.12 + /** 5.13 + * Does this global belong to a strict Context? 5.14 + * @return true if this global belongs to a strict Context 5.15 + */ 5.16 + public boolean isStrictContext(); 5.17 + 5.18 + /** 5.19 * Initialize standard builtin objects like "Object", "Array", "Function" etc. 5.20 * as well as our extension builtin objects like "Java", "JSAdapter" as properties 5.21 * of the global scope object.
6.1 --- a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Thu Sep 05 21:17:06 2013 +0530 6.2 +++ b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Mon Sep 09 20:10:41 2013 +0530 6.3 @@ -198,7 +198,7 @@ 6.4 final String propertyName = desc.getNameToken(2); 6.5 final String fullName = name.isEmpty() ? propertyName : name + "." + propertyName; 6.6 6.7 - final Context context = getContext(); 6.8 + final Context context = Context.getContextTrusted(); 6.9 6.10 Class<?> javaClass = null; 6.11 try {
7.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 05 21:17:06 2013 +0530 7.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Mon Sep 09 20:10:41 2013 +0530 7.3 @@ -120,9 +120,6 @@ 7.4 /** objects proto. */ 7.5 private ScriptObject proto; 7.6 7.7 - /** Context of the object, lazily cached. */ 7.8 - private Context context; 7.9 - 7.10 /** Object flags. */ 7.11 private int flags; 7.12 7.13 @@ -1043,40 +1040,11 @@ 7.14 } 7.15 7.16 /** 7.17 - * Return true if the script object context is strict 7.18 - * @return true if strict context 7.19 - */ 7.20 - public final boolean isStrictContext() { 7.21 - return getContext()._strict; 7.22 - } 7.23 - 7.24 - /** 7.25 - * Checks if this object belongs to the given context 7.26 - * @param ctx context to check against 7.27 - * @return true if this object belongs to the given context 7.28 - */ 7.29 - public final boolean isOfContext(final Context ctx) { 7.30 - return context == ctx; 7.31 - } 7.32 - 7.33 - /** 7.34 * Return the current context from the object's map. 7.35 * @return Current context. 7.36 */ 7.37 - protected final Context getContext() { 7.38 - if (context == null) { 7.39 - context = Context.fromClass(getClass()); 7.40 - } 7.41 - return context; 7.42 - } 7.43 - 7.44 - /** 7.45 - * Set the current context. 7.46 - * @param ctx context instance to set 7.47 - */ 7.48 - protected final void setContext(final Context ctx) { 7.49 - ctx.getClass(); 7.50 - this.context = ctx; 7.51 + protected Context getContext() { 7.52 + return Context.fromClass(getClass()); 7.53 } 7.54 7.55 /** 7.56 @@ -1482,9 +1450,10 @@ 7.57 /** 7.58 * Clears the properties from a ScriptObject 7.59 * (java.util.Map-like method to help ScriptObjectMirror implementation) 7.60 + * 7.61 + * @param strict strict mode or not 7.62 */ 7.63 - public void clear() { 7.64 - final boolean strict = isStrictContext(); 7.65 + public void clear(final boolean strict) { 7.66 final Iterator<String> iter = propertyIterator(); 7.67 while (iter.hasNext()) { 7.68 delete(iter.next(), strict); 7.69 @@ -1568,11 +1537,12 @@ 7.70 * 7.71 * @param key property key 7.72 * @param value property value 7.73 + * @param strict strict mode or not 7.74 * @return oldValue if property with same key existed already 7.75 */ 7.76 - public Object put(final Object key, final Object value) { 7.77 + public Object put(final Object key, final Object value, final boolean strict) { 7.78 final Object oldValue = get(key); 7.79 - set(key, value, isStrictContext()); 7.80 + set(key, value, strict); 7.81 return oldValue; 7.82 } 7.83 7.84 @@ -1582,9 +1552,9 @@ 7.85 * (java.util.Map-like method to help ScriptObjectMirror implementation) 7.86 * 7.87 * @param otherMap a {@literal <key,value>} map of properties to add 7.88 + * @param strict strict mode or not 7.89 */ 7.90 - public void putAll(final Map<?, ?> otherMap) { 7.91 - final boolean strict = isStrictContext(); 7.92 + public void putAll(final Map<?, ?> otherMap, final boolean strict) { 7.93 for (final Map.Entry<?, ?> entry : otherMap.entrySet()) { 7.94 set(entry.getKey(), entry.getValue(), strict); 7.95 } 7.96 @@ -1595,26 +1565,16 @@ 7.97 * (java.util.Map-like method to help ScriptObjectMirror implementation) 7.98 * 7.99 * @param key the key of the property 7.100 + * @param strict strict mode or not 7.101 * @return the oldValue of the removed property 7.102 */ 7.103 - public Object remove(final Object key) { 7.104 + public Object remove(final Object key, final boolean strict) { 7.105 final Object oldValue = get(key); 7.106 - delete(key, isStrictContext()); 7.107 + delete(key, strict); 7.108 return oldValue; 7.109 } 7.110 7.111 /** 7.112 - * Delete a property from the ScriptObject. 7.113 - * (to help ScriptObjectMirror implementation) 7.114 - * 7.115 - * @param key the key of the property 7.116 - * @return if the delete was successful or not 7.117 - */ 7.118 - public boolean delete(final Object key) { 7.119 - return delete(key, isStrictContext()); 7.120 - } 7.121 - 7.122 - /** 7.123 * Return the size of the ScriptObject - i.e. the number of properties 7.124 * it contains 7.125 * (java.util.Map-like method to help ScriptObjectMirror implementation) 7.126 @@ -2333,11 +2293,9 @@ 7.127 return; 7.128 } 7.129 7.130 - final boolean isStrict = isStrictContext(); 7.131 - 7.132 if (newLength > arrayLength) { 7.133 setArray(getArray().ensure(newLength - 1)); 7.134 - if (getArray().canDelete(arrayLength, (newLength - 1), isStrict)) { 7.135 + if (getArray().canDelete(arrayLength, (newLength - 1), false)) { 7.136 setArray(getArray().delete(arrayLength, (newLength - 1))); 7.137 } 7.138 return;
8.1 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Thu Sep 05 21:17:06 2013 +0530 8.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Mon Sep 09 20:10:41 2013 +0530 8.3 @@ -352,35 +352,6 @@ 8.4 } 8.5 8.6 /** 8.7 - * Check that the target function is associated with current Context. And also make sure that 'self', if 8.8 - * ScriptObject, is from current context. 8.9 - * 8.10 - * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 8.11 - * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} 8.12 - * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. 8.13 - * 8.14 - * @param target ScriptFunction object. 8.15 - * @param self Receiver in call. 8.16 - * @param args Call arguments. 8.17 - * @return Call result. 8.18 - */ 8.19 - public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) { 8.20 - final ScriptObject global = Context.getGlobalTrusted(); 8.21 - assert (global instanceof GlobalObject): "No current global set"; 8.22 - 8.23 - if (target.getContext() != global.getContext()) { 8.24 - throw new IllegalArgumentException("'target' function is not from current Context"); 8.25 - } 8.26 - 8.27 - if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) { 8.28 - throw new IllegalArgumentException("'self' object is not from current Context"); 8.29 - } 8.30 - 8.31 - // all in order - call real 'apply' 8.32 - return apply(target, self, args); 8.33 - } 8.34 - 8.35 - /** 8.36 * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve 8.37 * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} 8.38 * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. 8.39 @@ -401,28 +372,6 @@ 8.40 } 8.41 8.42 /** 8.43 - * Check that the target function is associated with current Context. 8.44 - * And also make sure that 'self', if ScriptObject, is from current context. 8.45 - * 8.46 - * Call a function as a constructor given args. 8.47 - * 8.48 - * @param target ScriptFunction object. 8.49 - * @param args Call arguments. 8.50 - * @return Constructor call result. 8.51 - */ 8.52 - public static Object checkAndConstruct(final ScriptFunction target, final Object... args) { 8.53 - final ScriptObject global = Context.getGlobalTrusted(); 8.54 - assert (global instanceof GlobalObject): "No current global set"; 8.55 - 8.56 - if (target.getContext() != global.getContext()) { 8.57 - throw new IllegalArgumentException("'target' function is not from current Context"); 8.58 - } 8.59 - 8.60 - // all in order - call real 'construct' 8.61 - return construct(target, args); 8.62 - } 8.63 - 8.64 - /** 8.65 * Call a script function as a constructor with given args. 8.66 * 8.67 * @param target ScriptFunction object. 8.68 @@ -520,9 +469,12 @@ 8.69 throw typeError(global, "cant.apply.with.to.null"); 8.70 } 8.71 8.72 - final ScriptObject withObject = new WithObject(scope, JSType.toScriptObject(global, expression)); 8.73 + final Object wrappedExpr = JSType.toScriptObject(global, expression); 8.74 + if (wrappedExpr instanceof ScriptObject) { 8.75 + return new WithObject(scope, (ScriptObject)wrappedExpr); 8.76 + } 8.77 8.78 - return withObject; 8.79 + throw typeError(global, "cant.apply.with.to.non.scriptobject"); 8.80 } 8.81 8.82 /** 8.83 @@ -534,7 +486,7 @@ 8.84 */ 8.85 public static ScriptObject closeWith(final ScriptObject scope) { 8.86 if (scope instanceof WithObject) { 8.87 - return scope.getProto(); 8.88 + return ((WithObject)scope).getParentScope(); 8.89 } 8.90 return scope; 8.91 }
9.1 --- a/src/jdk/nashorn/internal/runtime/WithObject.java Thu Sep 05 21:17:06 2013 +0530 9.2 +++ b/src/jdk/nashorn/internal/runtime/WithObject.java Mon Sep 09 20:10:41 2013 +0530 9.3 @@ -30,26 +30,26 @@ 9.4 import java.lang.invoke.MethodHandle; 9.5 import java.lang.invoke.MethodHandles; 9.6 import java.lang.invoke.MethodType; 9.7 +import java.lang.invoke.SwitchPoint; 9.8 import jdk.internal.dynalink.CallSiteDescriptor; 9.9 import jdk.internal.dynalink.linker.GuardedInvocation; 9.10 import jdk.internal.dynalink.linker.LinkRequest; 9.11 import jdk.internal.dynalink.support.CallSiteDescriptorFactory; 9.12 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 9.13 9.14 - 9.15 /** 9.16 * This class supports the handling of scope in a with body. 9.17 * 9.18 */ 9.19 public final class WithObject extends ScriptObject implements Scope { 9.20 - 9.21 + private static final MethodHandle WITHEXPRESSIONGUARD = findOwnMH("withExpressionGuard", boolean.class, Object.class, PropertyMap.class, SwitchPoint.class); 9.22 private static final MethodHandle WITHEXPRESSIONFILTER = findOwnMH("withFilterExpression", Object.class, Object.class); 9.23 private static final MethodHandle WITHSCOPEFILTER = findOwnMH("withFilterScope", Object.class, Object.class); 9.24 private static final MethodHandle BIND_TO_EXPRESSION_OBJ = findOwnMH("bindToExpression", Object.class, Object.class, Object.class); 9.25 private static final MethodHandle BIND_TO_EXPRESSION_FN = findOwnMH("bindToExpression", Object.class, ScriptFunction.class, Object.class); 9.26 9.27 /** With expression object. */ 9.28 - private final Object expression; 9.29 + private final ScriptObject expression; 9.30 9.31 /** 9.32 * Constructor 9.33 @@ -57,12 +57,13 @@ 9.34 * @param scope scope object 9.35 * @param expression with expression 9.36 */ 9.37 - WithObject(final ScriptObject scope, final Object expression) { 9.38 + WithObject(final ScriptObject scope, final ScriptObject expression) { 9.39 super(scope, null); 9.40 setIsScope(); 9.41 this.expression = expression; 9.42 } 9.43 9.44 + 9.45 /** 9.46 * Delete a property based on a key. 9.47 * @param key Any valid JavaScript value. 9.48 @@ -71,15 +72,13 @@ 9.49 */ 9.50 @Override 9.51 public boolean delete(final Object key, final boolean strict) { 9.52 - if (expression instanceof ScriptObject) { 9.53 - final ScriptObject self = (ScriptObject)expression; 9.54 - final String propName = JSType.toString(key); 9.55 + final ScriptObject self = expression; 9.56 + final String propName = JSType.toString(key); 9.57 9.58 - final FindProperty find = self.findProperty(propName, true); 9.59 + final FindProperty find = self.findProperty(propName, true); 9.60 9.61 - if (find != null) { 9.62 - return self.delete(propName, strict); 9.63 - } 9.64 + if (find != null) { 9.65 + return self.delete(propName, strict); 9.66 } 9.67 9.68 return false; 9.69 @@ -105,18 +104,16 @@ 9.70 name = null; 9.71 } 9.72 9.73 - if (expression instanceof ScriptObject) { 9.74 - self = (ScriptObject)expression; 9.75 - if (isNamedOperation) { 9.76 - find = self.findProperty(name, true); 9.77 - } 9.78 + self = expression; 9.79 + if (isNamedOperation) { 9.80 + find = self.findProperty(name, true); 9.81 + } 9.82 9.83 - if (find != null) { 9.84 - link = self.lookup(desc, request); 9.85 + if (find != null) { 9.86 + link = self.lookup(desc, request); 9.87 9.88 - if (link != null) { 9.89 - return fixExpressionCallSite(ndesc, link); 9.90 - } 9.91 + if (link != null) { 9.92 + return fixExpressionCallSite(ndesc, link); 9.93 } 9.94 } 9.95 9.96 @@ -126,7 +123,7 @@ 9.97 } 9.98 9.99 if (find != null) { 9.100 - return fixScopeCallSite(scope.lookup(desc, request)); 9.101 + return fixScopeCallSite(scope.lookup(desc, request), name); 9.102 } 9.103 9.104 // the property is not found - now check for 9.105 @@ -178,7 +175,7 @@ 9.106 link = scope.lookup(desc, request); 9.107 9.108 if (link != null) { 9.109 - return fixScopeCallSite(link); 9.110 + return fixScopeCallSite(link, name); 9.111 } 9.112 9.113 return null; 9.114 @@ -197,11 +194,9 @@ 9.115 */ 9.116 @Override 9.117 FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) { 9.118 - if (expression instanceof ScriptObject) { 9.119 - final FindProperty exprProperty = ((ScriptObject)expression).findProperty(key, deep, stopOnNonScope, start); 9.120 - if(exprProperty != null) { 9.121 - return exprProperty; 9.122 - } 9.123 + final FindProperty exprProperty = expression.findProperty(key, deep, stopOnNonScope, start); 9.124 + if (exprProperty != null) { 9.125 + return exprProperty; 9.126 } 9.127 return super.findProperty(key, deep, stopOnNonScope, start); 9.128 } 9.129 @@ -220,16 +215,17 @@ 9.130 * Get first parent scope that is not an instance of WithObject. 9.131 */ 9.132 private Scope getNonWithParent() { 9.133 - ScriptObject proto = getProto(); 9.134 + ScriptObject proto = getParentScope(); 9.135 9.136 while (proto != null && proto instanceof WithObject) { 9.137 - proto = proto.getProto(); 9.138 + proto = ((WithObject)proto).getParentScope(); 9.139 } 9.140 9.141 assert proto instanceof Scope : "with scope without parent scope"; 9.142 return (Scope) proto; 9.143 } 9.144 9.145 + 9.146 private static GuardedInvocation fixReceiverType(final GuardedInvocation link, final MethodHandle filter) { 9.147 // The receiver may be an Object or a ScriptObject. 9.148 final MethodType invType = link.getInvocation().type(); 9.149 @@ -256,9 +252,13 @@ 9.150 filterGuard(link, WITHEXPRESSIONFILTER)); 9.151 } 9.152 9.153 - private static GuardedInvocation fixScopeCallSite(final GuardedInvocation link) { 9.154 + private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name) { 9.155 final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER); 9.156 - return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), filterGuard(newLink, WITHSCOPEFILTER)); 9.157 + return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), 9.158 + MH.guardWithTest( 9.159 + expressionGuard(name), 9.160 + filterGuard(newLink, WITHSCOPEFILTER), 9.161 + MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class))); 9.162 } 9.163 9.164 private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) { 9.165 @@ -279,7 +279,6 @@ 9.166 return ((WithObject)receiver).expression; 9.167 } 9.168 9.169 - 9.170 @SuppressWarnings("unused") 9.171 private static Object bindToExpression(final Object fn, final Object receiver) { 9.172 return fn instanceof ScriptFunction ? bindToExpression((ScriptFunction) fn, receiver) : fn; 9.173 @@ -289,6 +288,17 @@ 9.174 return fn.makeBoundFunction(withFilterExpression(receiver), new Object[0]); 9.175 } 9.176 9.177 + private MethodHandle expressionGuard(final String name) { 9.178 + final PropertyMap map = expression.getMap(); 9.179 + final SwitchPoint sp = map.getProtoGetSwitchPoint(expression.getProto(), name); 9.180 + return MH.insertArguments(WITHEXPRESSIONGUARD, 1, map, sp); 9.181 + } 9.182 + 9.183 + @SuppressWarnings("unused") 9.184 + private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint sp) { 9.185 + return ((WithObject)receiver).expression.getMap() == map && (sp == null || !sp.hasBeenInvalidated()); 9.186 + } 9.187 + 9.188 /** 9.189 * Drops the WithObject wrapper from the scope. 9.190 * @param receiver WithObject wrapper. 9.191 @@ -302,10 +312,14 @@ 9.192 * Get the with expression for this {@code WithObject} 9.193 * @return the with expression 9.194 */ 9.195 - public Object getExpression() { 9.196 + public ScriptObject getExpression() { 9.197 return expression; 9.198 } 9.199 9.200 + public ScriptObject getParentScope() { 9.201 + return getProto(); 9.202 + } 9.203 + 9.204 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 9.205 return MH.findStatic(MethodHandles.lookup(), WithObject.class, name, MH.type(rtype, types)); 9.206 }
10.1 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties Thu Sep 05 21:17:06 2013 +0530 10.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Sep 09 20:10:41 2013 +0530 10.3 @@ -110,6 +110,7 @@ 10.4 type.error.cannot.get.default.number=Cannot get default number value 10.5 type.error.cant.apply.with.to.null=Cannot apply "with" to null 10.6 type.error.cant.apply.with.to.undefined=Cannot apply "with" to undefined 10.7 +type.error.cant.apply.with.to.non.scriptobject=Cannot apply "with" to non script object 10.8 type.error.in.with.non.object=Right hand side of "in" cannot be non-Object, found {0} 10.9 type.error.prototype.not.an.object="prototype" of {0} is not an Object, it is {1} 10.10 type.error.cant.load.script=Cannot load script from {0}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/script/basic/8024180/global_var_delete.js Mon Sep 09 20:10:41 2013 +0530 11.3 @@ -0,0 +1,50 @@ 11.4 +/* 11.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + */ 11.26 + 11.27 +/** 11.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 11.29 + * 11.30 + * @test 11.31 + * @run 11.32 + */ 11.33 + 11.34 + 11.35 +this.x = 44; 11.36 + 11.37 +function func() { 11.38 + with({ }) { 11.39 + print(x); 11.40 + } 11.41 +} 11.42 + 11.43 +func(); 11.44 + 11.45 +// delete global 'x' 11.46 +delete this.x; 11.47 + 11.48 +try { 11.49 + func(); 11.50 +} catch(e) { 11.51 + // expect ReferenceError 11.52 + print(e); 11.53 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/script/basic/8024180/global_var_delete.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 12.3 @@ -0,0 +1,2 @@ 12.4 +44 12.5 +ReferenceError: "x" is not defined
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/script/basic/8024180/global_var_shadow.js Mon Sep 09 20:10:41 2013 +0530 13.3 @@ -0,0 +1,45 @@ 13.4 +/* 13.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. 13.11 + * 13.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.15 + * version 2 for more details (a copy is included in the LICENSE file that 13.16 + * accompanied this code). 13.17 + * 13.18 + * You should have received a copy of the GNU General Public License version 13.19 + * 2 along with this work; if not, write to the Free Software Foundation, 13.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.21 + * 13.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.23 + * or visit www.oracle.com if you need additional information or have any 13.24 + * questions. 13.25 + */ 13.26 + 13.27 +/** 13.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 13.29 + * 13.30 + * @test 13.31 + * @run 13.32 + */ 13.33 + 13.34 +// global variable is shadowed by with 'expression' property 13.35 +var user = { name: 'foo' }; 13.36 + 13.37 +function func(locals) { 13.38 + with (locals) { 13.39 + print(user.name); 13.40 + } 13.41 +} 13.42 + 13.43 +// global user.name 'foo' printed 13.44 +func({}); 13.45 + 13.46 +// local user.name 'toto' printed 13.47 +func({ user: { name: 'toto' } }); 13.48 +
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/script/basic/8024180/global_var_shadow.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 14.3 @@ -0,0 +1,2 @@ 14.4 +foo 14.5 +toto
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/test/script/basic/8024180/scope_no_such_prop.js Mon Sep 09 20:10:41 2013 +0530 15.3 @@ -0,0 +1,51 @@ 15.4 +/* 15.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.7 + * 15.8 + * This code is free software; you can redistribute it and/or modify it 15.9 + * under the terms of the GNU General Public License version 2 only, as 15.10 + * published by the Free Software Foundation. 15.11 + * 15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15.15 + * version 2 for more details (a copy is included in the LICENSE file that 15.16 + * accompanied this code). 15.17 + * 15.18 + * You should have received a copy of the GNU General Public License version 15.19 + * 2 along with this work; if not, write to the Free Software Foundation, 15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 15.21 + * 15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 15.23 + * or visit www.oracle.com if you need additional information or have any 15.24 + * questions. 15.25 + */ 15.26 + 15.27 +/** 15.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 15.29 + * 15.30 + * @test 15.31 + * @run 15.32 + */ 15.33 + 15.34 +// __noSuchProperty__ defined here confuses 'with' 15.35 +// results in ReferenceError even when 'with' expression has 15.36 +// the property 15.37 + 15.38 +load("nashorn:mozilla_compat.js") 15.39 + 15.40 +function func(locals) { 15.41 + with (locals) { 15.42 + print(user.name); 15.43 + } 15.44 +} 15.45 + 15.46 +try { 15.47 + func({}); 15.48 +} catch (e) { 15.49 + print(e); 15.50 +} 15.51 + 15.52 +// 'toto' expected in the call below 15.53 +func({ user: { name: 'toto' } }); 15.54 +
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/test/script/basic/8024180/scope_no_such_prop.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 16.3 @@ -0,0 +1,2 @@ 16.4 +ReferenceError: user is not defined 16.5 +toto
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/test/script/basic/8024180/with_expr_prop_add.js Mon Sep 09 20:10:41 2013 +0530 17.3 @@ -0,0 +1,47 @@ 17.4 +/* 17.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.7 + * 17.8 + * This code is free software; you can redistribute it and/or modify it 17.9 + * under the terms of the GNU General Public License version 2 only, as 17.10 + * published by the Free Software Foundation. 17.11 + * 17.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 17.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17.15 + * version 2 for more details (a copy is included in the LICENSE file that 17.16 + * accompanied this code). 17.17 + * 17.18 + * You should have received a copy of the GNU General Public License version 17.19 + * 2 along with this work; if not, write to the Free Software Foundation, 17.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17.21 + * 17.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 17.23 + * or visit www.oracle.com if you need additional information or have any 17.24 + * questions. 17.25 + */ 17.26 + 17.27 +/** 17.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 17.29 + * 17.30 + * @test 17.31 + * @run 17.32 + */ 17.33 + 17.34 +var obj = {}; 17.35 +var x = "global x"; 17.36 + 17.37 +// adding property to 'with' xpression object should reflect 17.38 +// as variable inside the 'with' block. 17.39 +function func() { 17.40 + with(obj) { 17.41 + for (i = 0; i < 2; i++) { 17.42 + print(x); 17.43 + if (i == 0) { 17.44 + obj.x = "obj.x"; 17.45 + } 17.46 + } 17.47 + } 17.48 +} 17.49 + 17.50 +func();
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/test/script/basic/8024180/with_expr_prop_add.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 18.3 @@ -0,0 +1,2 @@ 18.4 +global x 18.5 +obj.x
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/test/script/basic/8024180/with_expr_proto_prop_add.js Mon Sep 09 20:10:41 2013 +0530 19.3 @@ -0,0 +1,49 @@ 19.4 +/* 19.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.7 + * 19.8 + * This code is free software; you can redistribute it and/or modify it 19.9 + * under the terms of the GNU General Public License version 2 only, as 19.10 + * published by the Free Software Foundation. 19.11 + * 19.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 19.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19.15 + * version 2 for more details (a copy is included in the LICENSE file that 19.16 + * accompanied this code). 19.17 + * 19.18 + * You should have received a copy of the GNU General Public License version 19.19 + * 2 along with this work; if not, write to the Free Software Foundation, 19.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19.21 + * 19.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19.23 + * or visit www.oracle.com if you need additional information or have any 19.24 + * questions. 19.25 + */ 19.26 + 19.27 +/** 19.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 19.29 + * 19.30 + * @test 19.31 + * @run 19.32 + */ 19.33 + 19.34 +var p = { }; 19.35 +var obj = Object.create(p); 19.36 + 19.37 +var x = "global x"; 19.38 + 19.39 +// adding property to __proto__ of 'with' expression should 19.40 +// reflect as a variable immediately. 19.41 +function func() { 19.42 + with(obj) { 19.43 + for (i = 0; i < 2; i++) { 19.44 + print(x); 19.45 + if (i == 0) { 19.46 + p.x = "p.x"; 19.47 + } 19.48 + } 19.49 + } 19.50 +} 19.51 + 19.52 +func();
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/test/script/basic/8024180/with_expr_proto_prop_add.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 20.3 @@ -0,0 +1,2 @@ 20.4 +global x 20.5 +p.x
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/test/script/basic/8024180/with_java_object.js Mon Sep 09 20:10:41 2013 +0530 21.3 @@ -0,0 +1,36 @@ 21.4 +/* 21.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.7 + * 21.8 + * This code is free software; you can redistribute it and/or modify it 21.9 + * under the terms of the GNU General Public License version 2 only, as 21.10 + * published by the Free Software Foundation. 21.11 + * 21.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 21.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21.15 + * version 2 for more details (a copy is included in the LICENSE file that 21.16 + * accompanied this code). 21.17 + * 21.18 + * You should have received a copy of the GNU General Public License version 21.19 + * 2 along with this work; if not, write to the Free Software Foundation, 21.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21.21 + * 21.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21.23 + * or visit www.oracle.com if you need additional information or have any 21.24 + * questions. 21.25 + */ 21.26 + 21.27 +/** 21.28 + * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements 21.29 + * 21.30 + * @test 21.31 + * @run 21.32 + */ 21.33 + 21.34 +// TypeError for with expression being non script object 21.35 +try { 21.36 + with(new java.lang.Object()) {} 21.37 +} catch (e) { 21.38 + print(e); 21.39 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/test/script/basic/8024180/with_java_object.js.EXPECTED Mon Sep 09 20:10:41 2013 +0530 22.3 @@ -0,0 +1,1 @@ 22.4 +TypeError: Cannot apply "with" to non script object
23.1 --- a/test/src/jdk/nashorn/internal/runtime/ContextTest.java Thu Sep 05 21:17:06 2013 +0530 23.2 +++ b/test/src/jdk/nashorn/internal/runtime/ContextTest.java Mon Sep 09 20:10:41 2013 +0530 23.3 @@ -64,6 +64,7 @@ 23.4 final Options options = new Options(""); 23.5 final ErrorManager errors = new ErrorManager(); 23.6 final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader()); 23.7 + final boolean strict = cx.getEnv()._strict; 23.8 final ScriptObject oldGlobal = Context.getGlobal(); 23.9 Context.setGlobal(cx.createGlobal()); 23.10 23.11 @@ -95,7 +96,7 @@ 23.12 assertEquals(sobj.size(), 2); 23.13 23.14 // add property 23.15 - sobj.put("zee", "hello"); 23.16 + sobj.put("zee", "hello", strict); 23.17 assertEquals(sobj.get("zee"), "hello"); 23.18 assertEquals(sobj.size(), 3); 23.19