Bug 1374462 - Fix super getprop and super getelem to not box 'this' values. (r=jorendorff)
authorShu-yu Guo <shu@rfrn.org>
Tue, 27 Jun 2017 13:17:59 -0700
changeset 600774 5cac74206e4e96e652289c80f2499827c0907162
parent 600773 71125aa849d31548fd7c188cecbd17cc287bd87f
child 600775 8517aa80bf2c83f6ede65c4afe17cfce344e4179
child 600867 e744a3029de20feeadf5b39f6039cd8959150ae4
push id65868
push userbmo:rail@mozilla.com
push dateTue, 27 Jun 2017 20:33:55 +0000
reviewersjorendorff
bugs1374462
milestone56.0a1
Bug 1374462 - Fix super getprop and super getelem to not box 'this' values. (r=jorendorff)
js/src/tests/ecma_6/Class/superPropHomeObject.js
js/src/tests/ecma_6/Class/superThisStrictNoBoxing.js
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
--- a/js/src/tests/ecma_6/Class/superPropHomeObject.js
+++ b/js/src/tests/ecma_6/Class/superPropHomeObject.js
@@ -20,20 +20,19 @@ class derived extends base {
 
 let derivedInstance = new derived();
 derivedInstance.test(derivedInstance);
 derivedInstance.testCPN(derivedInstance);
 
 let obj = { test: derivedInstance.test };
 obj.test(obj);
 
+// Classes are strict, so primitives are not boxed/turned into globals
 let testSolo = derivedInstance.test;
-// Hah! The engine is not prepared for non-object receivers, since this couldn't
-// happen before. Hope Waldo fixes this soon as he claims he will :)
-assertThrowsInstanceOf(() =>testSolo(undefined), TypeError);
+testSolo(undefined);
 
 let anotherObject = { };
 derivedInstance.test.call(anotherObject, anotherObject);
 
 let strThis = "this is not an object!";
 derivedInstance.test.call(strThis, strThis);
 
 // You can take the arrow function out of the super, ... or something like that
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superThisStrictNoBoxing.js
@@ -0,0 +1,31 @@
+class C {
+  get prop_this() { return this; }
+}
+
+var g_prop_this = 'prop_this';
+class D extends C {
+  super_prop() { return super.prop_this; }
+  super_elem() { return super[g_prop_this]; }
+}
+
+var barsym = Symbol("bar");
+
+// Test that primitive |this| values are not boxed, and undefined/null are not
+// globals for super.property.
+assertEq(new D().super_prop.call(3), 3);
+assertEq(new D().super_prop.call("foo"), "foo");
+assertEq(new D().super_prop.call(true), true);
+assertEq(new D().super_prop.call(barsym), barsym);
+assertEq(new D().super_prop.call(null), null);
+assertEq(new D().super_prop.call(undefined), undefined);
+
+// Ditto for super[elem]
+assertEq(new D().super_elem.call(3), 3);
+assertEq(new D().super_elem.call("foo"), "foo");
+assertEq(new D().super_elem.call(true), true);
+assertEq(new D().super_elem.call(barsym), barsym);
+assertEq(new D().super_elem.call(null), null);
+assertEq(new D().super_elem.call(undefined), undefined);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0, 0);
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -483,21 +483,21 @@ ToIdOperation(JSContext* cx, HandleScrip
     if (!ToPropertyKey(cx, idval, &id))
         return false;
 
     res.set(IdToValue(id));
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
-GetObjectElementOperation(JSContext* cx, JSOp op, JS::HandleObject obj, JS::HandleObject receiver,
+GetObjectElementOperation(JSContext* cx, JSOp op, JS::HandleObject obj, JS::HandleValue receiver,
                           HandleValue key, MutableHandleValue res)
 {
     MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM || op == JSOP_GETELEM_SUPER);
-    MOZ_ASSERT_IF(op == JSOP_GETELEM || op == JSOP_CALLELEM, obj == receiver);
+    MOZ_ASSERT_IF(op == JSOP_GETELEM || op == JSOP_CALLELEM, obj == &receiver.toObject());
 
     do {
         uint32_t index;
         if (IsDefinitelyIndex(key, &index)) {
             if (GetElementNoGC(cx, obj, receiver, index, res.address()))
                 break;
 
             if (!GetElement(cx, obj, receiver, index, res))
@@ -621,18 +621,19 @@ GetElementOperation(JSContext* cx, JSOp 
         }
     }
 
     if (lref.isPrimitive()) {
         RootedValue thisv(cx, lref);
         return GetPrimitiveElementOperation(cx, op, thisv, rref, res);
     }
 
-    RootedObject thisv(cx, &lref.toObject());
-    return GetObjectElementOperation(cx, op, thisv, thisv, rref, res);
+    RootedObject obj(cx, &lref.toObject());
+    RootedValue thisv(cx, lref);
+    return GetObjectElementOperation(cx, op, obj, thisv, rref, res);
 }
 
 static MOZ_ALWAYS_INLINE JSString*
 TypeOfOperation(const Value& v, JSRuntime* rt)
 {
     JSType type = js::TypeOfValue(v);
     return TypeName(type, *rt->commonNames);
 }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2781,18 +2781,17 @@ CASE(JSOP_CALLPROP)
 
     TypeScript::Monitor(cx, script, REGS.pc, lval);
     assertSameCompartmentDebugOnly(cx, lval);
 }
 END_CASE(JSOP_GETPROP)
 
 CASE(JSOP_GETPROP_SUPER)
 {
-    ReservedRooted<JSObject*> receiver(&rootObject0);
-    FETCH_OBJECT(cx, -2, receiver);
+    ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-2]);
     ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
     MutableHandleValue rref = REGS.stackHandleAt(-2);
 
     if (!GetProperty(cx, obj, receiver, script->getName(REGS.pc), rref))
         goto error;
 
     TypeScript::Monitor(cx, script, REGS.pc, rref);
     assertSameCompartmentDebugOnly(cx, rref);
@@ -2906,19 +2905,18 @@ CASE(JSOP_CALLELEM)
 
     TypeScript::Monitor(cx, script, REGS.pc, res);
     REGS.sp--;
 }
 END_CASE(JSOP_GETELEM)
 
 CASE(JSOP_GETELEM_SUPER)
 {
-    HandleValue rval = REGS.stackHandleAt(-3);
-    ReservedRooted<JSObject*> receiver(&rootObject0);
-    FETCH_OBJECT(cx, -2, receiver);
+    ReservedRooted<Value> rval(&rootValue0, REGS.sp[-3]);
+    ReservedRooted<Value> receiver(&rootValue1, REGS.sp[-2]);
     ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
 
     MutableHandleValue res = REGS.stackHandleAt(-3);
 
     // Since we have asserted that obj has to be an object, it cannot be
     // either optimized arguments, or indeed any primitive. This simplifies
     // our task some.
     if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, rval, res))