8024180: Incorrect handling of expression and parent scope in 'with' statements
authorsundar
Mon, 09 Sep 2013 20:10:41 +0530
changeset 19884 1bacbaa1bfc7
parent 19883 aae0838ac6ee
child 19885 541c4aaad83d
child 19886 3386a0c77420
8024180: Incorrect handling of expression and parent scope in 'with' statements Reviewed-by: jlaskey, hannesw
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/test/script/basic/8024180/global_var_delete.js
nashorn/test/script/basic/8024180/global_var_delete.js.EXPECTED
nashorn/test/script/basic/8024180/global_var_shadow.js
nashorn/test/script/basic/8024180/global_var_shadow.js.EXPECTED
nashorn/test/script/basic/8024180/scope_no_such_prop.js
nashorn/test/script/basic/8024180/scope_no_such_prop.js.EXPECTED
nashorn/test/script/basic/8024180/with_expr_prop_add.js
nashorn/test/script/basic/8024180/with_expr_prop_add.js.EXPECTED
nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js
nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js.EXPECTED
nashorn/test/script/basic/8024180/with_java_object.js
nashorn/test/script/basic/8024180/with_java_object.js.EXPECTED
nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Sep 09 20:10:41 2013 +0530
@@ -315,7 +315,7 @@
             final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz;
             realSelf = mirror.getScriptObject();
             realGlobal = mirror.getHomeGlobal();
-            if (! realGlobal.isOfContext(nashornContext)) {
+            if (! isOfContext(realGlobal, nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
         } else if (thiz instanceof ScriptObject) {
@@ -326,7 +326,7 @@
                 throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
             }
 
-            if (! realGlobal.isOfContext(nashornContext)) {
+            if (! isOfContext(realGlobal, nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
         }
@@ -394,7 +394,7 @@
     // Retrieve nashorn Global object from a given ScriptObjectMirror
     private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) {
         ScriptObject sobj = mirror.getScriptObject();
-        if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) {
+        if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) {
             return sobj;
         }
 
@@ -470,7 +470,7 @@
         ScriptObjectMirror selfMirror = null;
         if (selfObject instanceof ScriptObjectMirror) {
             selfMirror = (ScriptObjectMirror)selfObject;
-            if (! selfMirror.getHomeGlobal().isOfContext(nashornContext)) {
+            if (! isOfContext(selfMirror.getHomeGlobal(), nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
         } else if (selfObject instanceof ScriptObject) {
@@ -481,7 +481,7 @@
                 throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
             }
 
-            if (! oldGlobal.isOfContext(nashornContext)) {
+            if (! isOfContext(oldGlobal, nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
 
@@ -617,4 +617,9 @@
         }
         return true;
     }
+
+    private static boolean isOfContext(final ScriptObject global, final Context context) {
+        assert global instanceof GlobalObject: "Not a Global object";
+        return ((GlobalObject)global).isOfContext(context);
+    }
 }
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Mon Sep 09 20:10:41 2013 +0530
@@ -42,6 +42,7 @@
 import java.util.concurrent.Callable;
 import javax.script.Bindings;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.GlobalObject;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -62,6 +63,7 @@
 
     private final ScriptObject sobj;
     private final ScriptObject global;
+    private final boolean strict;
 
     @Override
     public boolean equals(final Object other) {
@@ -101,7 +103,7 @@
             final Object val = functionName == null? sobj : sobj.get(functionName);
             if (val instanceof ScriptFunction) {
                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
-                return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
+                return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
                 return ((ScriptObjectMirror)val).call(null, args);
             }
@@ -131,7 +133,7 @@
             final Object val = functionName == null? sobj : sobj.get(functionName);
             if (val instanceof ScriptFunction) {
                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
-                return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
+                return wrap(ScriptRuntime.construct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
                 return ((ScriptObjectMirror)val).newObject(null, args);
             }
@@ -197,7 +199,7 @@
     public void setSlot(final int index, final Object value) {
         inGlobal(new Callable<Void>() {
             @Override public Void call() {
-                sobj.set(index, unwrap(value, global), global.isStrictContext());
+                sobj.set(index, unwrap(value, global), strict);
                 return null;
             }
         });
@@ -209,7 +211,7 @@
     public void clear() {
         inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                sobj.clear();
+                sobj.clear(strict);
                 return null;
             }
         });
@@ -292,7 +294,7 @@
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
                 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
-                return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global));
+                return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
             }
         });
     }
@@ -303,7 +305,6 @@
         final boolean globalChanged = (oldGlobal != global);
         inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                final boolean strict = global.isStrictContext();
                 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
                     final Object value = entry.getValue();
                     final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
@@ -318,7 +319,7 @@
     public Object remove(final Object key) {
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return wrap(sobj.remove(unwrap(key, global)), global);
+                return wrap(sobj.remove(unwrap(key, global), strict), global);
             }
         });
     }
@@ -333,7 +334,7 @@
     public boolean delete(final Object key) {
         return inGlobal(new Callable<Boolean>() {
             @Override public Boolean call() {
-                return sobj.delete(unwrap(key, global));
+                return sobj.delete(unwrap(key, global), strict);
             }
         });
     }
@@ -637,10 +638,11 @@
 
     ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
         assert sobj != null : "ScriptObjectMirror on null!";
-        assert global != null : "null global for ScriptObjectMirror!";
+        assert global instanceof GlobalObject : "global is not a GlobalObject";
 
         this.sobj = sobj;
         this.global = global;
+        this.strict = ((GlobalObject)global).isStrictContext();
     }
 
     // accessors for script engine
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Mon Sep 09 20:10:41 2013 +0530
@@ -412,6 +412,14 @@
     // initialized by nasgen
     private static PropertyMap $nasgenmap$;
 
+    // context to which this global belongs to
+    private final Context context;
+
+    @Override
+    protected Context getContext() {
+        return context;
+    }
+
     // performs initialization checks for Global constructor and returns the
     // PropertyMap, if everything is fine.
     private static PropertyMap checkAndGetMap(final Context context) {
@@ -439,7 +447,7 @@
      */
     public Global(final Context context) {
         super(checkAndGetMap(context));
-        this.setContext(context);
+        this.context = context;
         this.setIsScope();
 
         final int cacheSize = context.getEnv()._class_cache_size;
@@ -482,6 +490,16 @@
     // GlobalObject interface implementation
 
     @Override
+    public boolean isOfContext(final Context context) {
+        return this.context == context;
+    }
+
+    @Override
+    public boolean isStrictContext() {
+        return context.getEnv()._strict;
+    }
+
+    @Override
     public void initBuiltinObjects() {
         if (this.builtinObject != null) {
             // already initialized, just return
@@ -1765,7 +1783,7 @@
             // do not fill $ENV if we have a security manager around
             // Retrieve current state of ENV variables.
             final ScriptObject env = newObject();
-            env.putAll(System.getenv());
+            env.putAll(System.getenv(), scriptEnv._strict);
             addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
         } else {
             addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Mon Sep 09 20:10:41 2013 +0530
@@ -573,7 +573,7 @@
         setGlobalTrusted(newGlobal);
 
         final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY :  ScriptObjectMirror.wrapArray(args, oldGlobal);
-        newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped));
+        newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped), env._strict);
 
         try {
             // wrap objects from newGlobal's world as mirrors - but if result
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java	Mon Sep 09 20:10:41 2013 +0530
@@ -37,6 +37,18 @@
 
 public interface GlobalObject {
     /**
+     * Is this global of the given Context?
+     * @return true if this global belongs to the given Context
+     */
+    public boolean isOfContext(Context context);
+
+    /**
+     * Does this global belong to a strict Context?
+     * @return true if this global belongs to a strict Context
+     */
+    public boolean isStrictContext();
+
+    /**
      * Initialize standard builtin objects like "Object", "Array", "Function" etc.
      * as well as our extension builtin objects like "Java", "JSAdapter" as properties
      * of the global scope object.
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Mon Sep 09 20:10:41 2013 +0530
@@ -198,7 +198,7 @@
         final String propertyName = desc.getNameToken(2);
         final String fullName     = name.isEmpty() ? propertyName : name + "." + propertyName;
 
-        final Context context = getContext();
+        final Context context = Context.getContextTrusted();
 
         Class<?> javaClass = null;
         try {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Sep 09 20:10:41 2013 +0530
@@ -120,9 +120,6 @@
     /** objects proto. */
     private ScriptObject proto;
 
-    /** Context of the object, lazily cached. */
-    private Context context;
-
     /** Object flags. */
     private int flags;
 
@@ -1043,40 +1040,11 @@
     }
 
     /**
-     * Return true if the script object context is strict
-     * @return true if strict context
-     */
-    public final boolean isStrictContext() {
-        return getContext()._strict;
-    }
-
-    /**
-     * Checks if this object belongs to the given context
-     * @param ctx context to check against
-     * @return true if this object belongs to the given context
-     */
-    public final boolean isOfContext(final Context ctx) {
-        return context == ctx;
-    }
-
-    /**
      * Return the current context from the object's map.
      * @return Current context.
      */
-    protected final Context getContext() {
-        if (context == null) {
-            context = Context.fromClass(getClass());
-        }
-        return context;
-    }
-
-    /**
-     * Set the current context.
-     * @param ctx context instance to set
-     */
-    protected final void setContext(final Context ctx) {
-        ctx.getClass();
-        this.context = ctx;
+    protected Context getContext() {
+        return Context.fromClass(getClass());
     }
 
     /**
@@ -1482,9 +1450,10 @@
     /**
      * Clears the properties from a ScriptObject
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
+     *
+     * @param strict strict mode or not
      */
-    public void clear() {
-        final boolean strict = isStrictContext();
+    public void clear(final boolean strict) {
         final Iterator<String> iter = propertyIterator();
         while (iter.hasNext()) {
             delete(iter.next(), strict);
@@ -1568,11 +1537,12 @@
      *
      * @param key property key
      * @param value property value
+     * @param strict strict mode or not
      * @return oldValue if property with same key existed already
      */
-    public Object put(final Object key, final Object value) {
+    public Object put(final Object key, final Object value, final boolean strict) {
         final Object oldValue = get(key);
-        set(key, value, isStrictContext());
+        set(key, value, strict);
         return oldValue;
     }
 
@@ -1582,9 +1552,9 @@
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
      *
      * @param otherMap a {@literal <key,value>} map of properties to add
+     * @param strict strict mode or not
      */
-    public void putAll(final Map<?, ?> otherMap) {
-        final boolean strict = isStrictContext();
+    public void putAll(final Map<?, ?> otherMap, final boolean strict) {
         for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
             set(entry.getKey(), entry.getValue(), strict);
         }
@@ -1595,26 +1565,16 @@
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
      *
      * @param key the key of the property
+     * @param strict strict mode or not
      * @return the oldValue of the removed property
      */
-    public Object remove(final Object key) {
+    public Object remove(final Object key, final boolean strict) {
         final Object oldValue = get(key);
-        delete(key, isStrictContext());
+        delete(key, strict);
         return oldValue;
     }
 
     /**
-     * Delete a property from the ScriptObject.
-     * (to help ScriptObjectMirror implementation)
-     *
-     * @param key the key of the property
-     * @return if the delete was successful or not
-     */
-    public boolean delete(final Object key) {
-        return delete(key, isStrictContext());
-    }
-
-    /**
      * Return the size of the ScriptObject - i.e. the number of properties
      * it contains
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
@@ -2333,11 +2293,9 @@
            return;
        }
 
-       final boolean isStrict = isStrictContext();
-
        if (newLength > arrayLength) {
            setArray(getArray().ensure(newLength - 1));
-            if (getArray().canDelete(arrayLength, (newLength - 1), isStrict)) {
+            if (getArray().canDelete(arrayLength, (newLength - 1), false)) {
                setArray(getArray().delete(arrayLength, (newLength - 1)));
            }
            return;
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Mon Sep 09 20:10:41 2013 +0530
@@ -352,35 +352,6 @@
     }
 
     /**
-     * Check that the target function is associated with current Context. And also make sure that 'self', if
-     * ScriptObject, is from current context.
-     *
-     * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
-     * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
-     * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
-     *
-     * @param target ScriptFunction object.
-     * @param self   Receiver in call.
-     * @param args   Call arguments.
-     * @return Call result.
-     */
-    public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) {
-        final ScriptObject global = Context.getGlobalTrusted();
-        assert (global instanceof GlobalObject): "No current global set";
-
-        if (target.getContext() != global.getContext()) {
-            throw new IllegalArgumentException("'target' function is not from current Context");
-        }
-
-        if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) {
-            throw new IllegalArgumentException("'self' object is not from current Context");
-        }
-
-        // all in order - call real 'apply'
-        return apply(target, self, args);
-    }
-
-    /**
      * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
      * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
      * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
@@ -401,28 +372,6 @@
     }
 
     /**
-     * Check that the target function is associated with current Context.
-     * And also make sure that 'self', if ScriptObject, is from current context.
-     *
-     * Call a function as a constructor given args.
-     *
-     * @param target ScriptFunction object.
-     * @param args   Call arguments.
-     * @return Constructor call result.
-     */
-    public static Object checkAndConstruct(final ScriptFunction target, final Object... args) {
-        final ScriptObject global = Context.getGlobalTrusted();
-        assert (global instanceof GlobalObject): "No current global set";
-
-        if (target.getContext() != global.getContext()) {
-            throw new IllegalArgumentException("'target' function is not from current Context");
-        }
-
-        // all in order - call real 'construct'
-        return construct(target, args);
-    }
-
-    /**
      * Call a script function as a constructor with given args.
      *
      * @param target ScriptFunction object.
@@ -520,9 +469,12 @@
             throw typeError(global, "cant.apply.with.to.null");
         }
 
-        final ScriptObject withObject = new WithObject(scope, JSType.toScriptObject(global, expression));
+        final Object wrappedExpr = JSType.toScriptObject(global, expression);
+        if (wrappedExpr instanceof ScriptObject) {
+            return new WithObject(scope, (ScriptObject)wrappedExpr);
+        }
 
-        return withObject;
+        throw typeError(global, "cant.apply.with.to.non.scriptobject");
     }
 
     /**
@@ -534,7 +486,7 @@
      */
     public static ScriptObject closeWith(final ScriptObject scope) {
         if (scope instanceof WithObject) {
-            return scope.getProto();
+            return ((WithObject)scope).getParentScope();
         }
         return scope;
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Mon Sep 09 20:10:41 2013 +0530
@@ -30,26 +30,26 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 
-
 /**
  * This class supports the handling of scope in a with body.
  *
  */
 public final class WithObject extends ScriptObject implements Scope {
-
+    private static final MethodHandle WITHEXPRESSIONGUARD    = findOwnMH("withExpressionGuard",  boolean.class, Object.class, PropertyMap.class, SwitchPoint.class);
     private static final MethodHandle WITHEXPRESSIONFILTER   = findOwnMH("withFilterExpression", Object.class, Object.class);
     private static final MethodHandle WITHSCOPEFILTER        = findOwnMH("withFilterScope",      Object.class, Object.class);
     private static final MethodHandle BIND_TO_EXPRESSION_OBJ = findOwnMH("bindToExpression",     Object.class, Object.class, Object.class);
     private static final MethodHandle BIND_TO_EXPRESSION_FN  = findOwnMH("bindToExpression",     Object.class, ScriptFunction.class, Object.class);
 
     /** With expression object. */
-    private final Object expression;
+    private final ScriptObject expression;
 
     /**
      * Constructor
@@ -57,12 +57,13 @@
      * @param scope scope object
      * @param expression with expression
      */
-    WithObject(final ScriptObject scope, final Object expression) {
+    WithObject(final ScriptObject scope, final ScriptObject expression) {
         super(scope, null);
         setIsScope();
         this.expression = expression;
     }
 
+
     /**
      * Delete a property based on a key.
      * @param key Any valid JavaScript value.
@@ -71,15 +72,13 @@
      */
     @Override
     public boolean delete(final Object key, final boolean strict) {
-        if (expression instanceof ScriptObject) {
-            final ScriptObject self = (ScriptObject)expression;
-            final String propName = JSType.toString(key);
+        final ScriptObject self = expression;
+        final String propName = JSType.toString(key);
 
-            final FindProperty find = self.findProperty(propName, true);
+        final FindProperty find = self.findProperty(propName, true);
 
-            if (find != null) {
-                return self.delete(propName, strict);
-            }
+        if (find != null) {
+            return self.delete(propName, strict);
         }
 
         return false;
@@ -105,18 +104,16 @@
             name = null;
         }
 
-        if (expression instanceof ScriptObject) {
-            self = (ScriptObject)expression;
-            if (isNamedOperation) {
-                find = self.findProperty(name, true);
-            }
+        self = expression;
+        if (isNamedOperation) {
+             find = self.findProperty(name, true);
+        }
 
-            if (find != null) {
-                link = self.lookup(desc, request);
+        if (find != null) {
+            link = self.lookup(desc, request);
 
-                if (link != null) {
-                    return fixExpressionCallSite(ndesc, link);
-                }
+            if (link != null) {
+                return fixExpressionCallSite(ndesc, link);
             }
         }
 
@@ -126,7 +123,7 @@
         }
 
         if (find != null) {
-            return fixScopeCallSite(scope.lookup(desc, request));
+            return fixScopeCallSite(scope.lookup(desc, request), name);
         }
 
         // the property is not found - now check for
@@ -178,7 +175,7 @@
         link = scope.lookup(desc, request);
 
         if (link != null) {
-            return fixScopeCallSite(link);
+            return fixScopeCallSite(link, name);
         }
 
         return null;
@@ -197,11 +194,9 @@
      */
     @Override
     FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) {
-        if (expression instanceof ScriptObject) {
-            final FindProperty exprProperty = ((ScriptObject)expression).findProperty(key, deep, stopOnNonScope, start);
-            if(exprProperty != null) {
-                return exprProperty;
-            }
+        final FindProperty exprProperty = expression.findProperty(key, deep, stopOnNonScope, start);
+        if (exprProperty != null) {
+             return exprProperty;
         }
         return super.findProperty(key, deep, stopOnNonScope, start);
     }
@@ -220,16 +215,17 @@
      * Get first parent scope that is not an instance of WithObject.
      */
     private Scope getNonWithParent() {
-        ScriptObject proto = getProto();
+        ScriptObject proto = getParentScope();
 
         while (proto != null && proto instanceof WithObject) {
-            proto = proto.getProto();
+            proto = ((WithObject)proto).getParentScope();
         }
 
         assert proto instanceof Scope : "with scope without parent scope";
         return (Scope) proto;
     }
 
+
     private static GuardedInvocation fixReceiverType(final GuardedInvocation link, final MethodHandle filter) {
         // The receiver may be an Object or a ScriptObject.
         final MethodType invType = link.getInvocation().type();
@@ -256,9 +252,13 @@
                 filterGuard(link, WITHEXPRESSIONFILTER));
     }
 
-    private static GuardedInvocation fixScopeCallSite(final GuardedInvocation link) {
+    private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name) {
         final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
-        return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), filterGuard(newLink, WITHSCOPEFILTER));
+        return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER),
+            MH.guardWithTest(
+                expressionGuard(name),
+                filterGuard(newLink, WITHSCOPEFILTER),
+                MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class)));
     }
 
     private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) {
@@ -279,7 +279,6 @@
         return ((WithObject)receiver).expression;
     }
 
-
     @SuppressWarnings("unused")
     private static Object bindToExpression(final Object fn, final Object receiver) {
         return fn instanceof ScriptFunction ? bindToExpression((ScriptFunction) fn, receiver) : fn;
@@ -289,6 +288,17 @@
         return fn.makeBoundFunction(withFilterExpression(receiver), new Object[0]);
     }
 
+    private MethodHandle expressionGuard(final String name) {
+        final PropertyMap map = expression.getMap();
+        final SwitchPoint sp = map.getProtoGetSwitchPoint(expression.getProto(), name);
+        return MH.insertArguments(WITHEXPRESSIONGUARD, 1, map, sp);
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint sp) {
+        return ((WithObject)receiver).expression.getMap() == map && (sp == null || !sp.hasBeenInvalidated());
+    }
+
     /**
      * Drops the WithObject wrapper from the scope.
      * @param receiver WithObject wrapper.
@@ -302,10 +312,14 @@
      * Get the with expression for this {@code WithObject}
      * @return the with expression
      */
-    public Object getExpression() {
+    public ScriptObject getExpression() {
         return expression;
     }
 
+    public ScriptObject getParentScope() {
+        return getProto();
+    }
+
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), WithObject.class, name, MH.type(rtype, types));
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Mon Sep 09 20:10:41 2013 +0530
@@ -110,6 +110,7 @@
 type.error.cannot.get.default.number=Cannot get default number value
 type.error.cant.apply.with.to.null=Cannot apply "with" to null
 type.error.cant.apply.with.to.undefined=Cannot apply "with" to undefined
+type.error.cant.apply.with.to.non.scriptobject=Cannot apply "with" to non script object
 type.error.in.with.non.object=Right hand side of "in" cannot be non-Object, found {0}
 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}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_delete.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+
+this.x = 44;
+
+function func() {
+    with({ }) {
+        print(x);
+    }
+}
+
+func();
+
+// delete global 'x'
+delete this.x;
+
+try {
+    func();
+} catch(e) {
+    // expect ReferenceError
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_delete.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,2 @@
+44
+ReferenceError: "x" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_shadow.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// global variable is shadowed by with 'expression' property
+var  user = { name: 'foo' };
+
+function func(locals) {
+    with (locals) {
+        print(user.name);
+    }
+}
+
+// global user.name 'foo' printed
+func({});
+
+// local user.name 'toto' printed
+func({ user: { name: 'toto' } });
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_shadow.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,2 @@
+foo
+toto
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/scope_no_such_prop.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// __noSuchProperty__ defined here confuses 'with'
+// results in ReferenceError even when 'with' expression has
+// the property
+
+load("nashorn:mozilla_compat.js")
+
+function func(locals) {
+    with (locals) {
+        print(user.name);
+    }
+}
+
+try {
+    func({});
+} catch (e) {
+    print(e);
+}
+
+// 'toto' expected in the call below
+func({ user: { name: 'toto' } });
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/scope_no_such_prop.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,2 @@
+ReferenceError: user is not defined
+toto
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_prop_add.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+var obj = {};
+var x = "global x";
+
+// adding property to 'with' xpression object should reflect
+// as variable inside the 'with' block.
+function func() {
+    with(obj) {
+        for (i = 0; i < 2; i++) {
+            print(x);
+            if (i == 0) {
+                obj.x = "obj.x";
+            }
+        }
+    }
+}
+
+func();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_prop_add.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,2 @@
+global x
+obj.x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+var p =  { };
+var obj = Object.create(p);
+
+var x = "global x";
+
+// adding property to __proto__ of 'with' expression should
+// reflect as a variable immediately.
+function func() {
+    with(obj) {
+        for (i = 0; i < 2; i++) {
+            print(x);
+            if (i == 0) {
+                p.x = "p.x";
+            }
+        } 
+    }
+}
+
+func();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,2 @@
+global x
+p.x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_java_object.js	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * 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-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// TypeError for with expression being non script object
+try {
+    with(new java.lang.Object()) {}
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_java_object.js.EXPECTED	Mon Sep 09 20:10:41 2013 +0530
@@ -0,0 +1,1 @@
+TypeError: Cannot apply "with" to non script object
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java	Thu Sep 05 21:17:06 2013 +0530
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java	Mon Sep 09 20:10:41 2013 +0530
@@ -64,6 +64,7 @@
         final Options options = new Options("");
         final ErrorManager errors = new ErrorManager();
         final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader());
+        final boolean strict = cx.getEnv()._strict;
         final ScriptObject oldGlobal = Context.getGlobal();
         Context.setGlobal(cx.createGlobal());
 
@@ -95,7 +96,7 @@
             assertEquals(sobj.size(), 2);
 
             // add property
-            sobj.put("zee", "hello");
+            sobj.put("zee", "hello", strict);
             assertEquals(sobj.get("zee"), "hello");
             assertEquals(sobj.size(), 3);