Bug 1394490 - Support NSVOs with JSOP_FUNCTIONTHIS fallback draft
authorTed Campbell <tcampbell@mozilla.com>
Thu, 31 Aug 2017 16:25:39 -0400
changeset 657508 b2619f543a38779b87494bc46812418ae15ef74b
parent 657507 2c68222aaa722ef973bceefd676e213fe42a07d4
child 657509 67e2d58a689d477be2c6e969ce451d6cb2d67ddb
push id77543
push userbmo:tcampbell@mozilla.com
push dateFri, 01 Sep 2017 15:47:07 +0000
bugs1394490
milestone57.0a1
Bug 1394490 - Support NSVOs with JSOP_FUNCTIONTHIS fallback When a non-strict function is called with undefined |this|, we must substitute in the global |this|. This patch fixes this behavior when a NonSyntacticVariablesObject is on envChain. MozReview-Commit-ID: C3oOVQQNhNa
js/src/vm/EnvironmentObject.h
js/src/vm/Interpreter.cpp
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -1079,16 +1079,24 @@ IsExtensibleLexicalEnvironment(JSObject*
 
 inline bool
 IsGlobalLexicalEnvironment(JSObject* env)
 {
     return env->is<LexicalEnvironmentObject>() &&
            env->as<LexicalEnvironmentObject>().isGlobal();
 }
 
+inline bool
+IsNSVOLexicalEnvironment(JSObject* env)
+{
+    return env->is<LexicalEnvironmentObject>() &&
+           env->as<LexicalEnvironmentObject>().enclosingEnvironment()
+                                              .is<NonSyntacticVariablesObject>();
+}
+
 inline JSObject*
 MaybeUnwrapWithEnvironment(JSObject* env)
 {
     if (env->is<WithEnvironmentObject>())
         return &env->as<WithEnvironmentObject>().object();
     return env;
 }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -90,17 +90,17 @@ js::BoxNonStrictThis(JSContext* cx, Hand
 {
     /*
      * Check for SynthesizeFrame poisoning and fast constructors which
      * didn't check their callee properly.
      */
     MOZ_ASSERT(!thisv.isMagic());
 
     if (thisv.isNullOrUndefined()) {
-        vp.set(GetThisValue(cx->global()));
+        vp.set(cx->global()->lexicalEnvironment().thisValue());
         return true;
     }
 
     if (thisv.isObject()) {
         vp.set(thisv);
         return true;
     }
 
@@ -122,16 +122,41 @@ js::GetFunctionThis(JSContext* cx, Abstr
         frame.callee()->strict() ||
         frame.callee()->isSelfHostedBuiltin())
     {
         res.set(frame.thisArgument());
         return true;
     }
 
     RootedValue thisv(cx, frame.thisArgument());
+
+    // If there is a NSVO on environment chain, use it as basis for fallback
+    // global |this|. This gives a consistent definition of global lexical
+    // |this| between function and global contexts.
+    //
+    // NOTE: If only non-syntactic WithEnvironments are on the chain, we use
+    // the global lexical |this| value.
+    if (frame.script()->hasNonSyntacticScope() && thisv.isNullOrUndefined()) {
+        RootedObject env(cx, frame.environmentChain());
+        while (true) {
+            if (IsNSVOLexicalEnvironment(env) || IsGlobalLexicalEnvironment(env)) {
+                res.set(GetThisValue(env));
+                return true;
+            }
+            if (!env->enclosingEnvironment()) {
+                // This can only happen in Debugger eval frames: in that case we
+                // don't always have a global lexical env, see EvaluateInEnv.
+                MOZ_ASSERT(env->is<GlobalObject>());
+                res.set(GetThisValue(env));
+                return true;
+            }
+            env = env->enclosingEnvironment();
+        }
+    }
+
     return BoxNonStrictThis(cx, thisv, res);
 }
 
 void
 js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, MutableHandleValue res)
 {
     RootedObject env(cx, envChain);
     while (true) {