Bug 603201 - Change GetProperty receiver argument to Value in JS. r=efaust
authorTom Schuster <evilpies@gmail.com>
Fri, 18 Sep 2015 00:14:33 +0200
changeset 297472 0dd901033bab9d3b1b9e2c8bbc914b42496afb06
parent 297471 3c9f7ca5a12f9b61db3c4cbe1bbf948427ed24dc
child 297473 81385142227216ba4f0a73a11dd1a0ef8df63c4e
push id962
push userjlund@mozilla.com
push dateFri, 04 Dec 2015 23:28:54 +0000
treeherdermozilla-release@23a2d286e80f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs603201
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 603201 - Change GetProperty receiver argument to Value in JS. r=efaust
js/public/Class.h
js/public/Proxy.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/jit/BaselineIC.cpp
js/src/jit/IonCaches.cpp
js/src/jit/JitFrames.cpp
js/src/jit/JitFrames.h
js/src/jsfriendapi.h
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DirectProxyHandler.cpp
js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedDirectProxyHandler.h
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.h
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/ScopeObject.cpp
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -353,17 +353,17 @@ typedef bool
                      JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
 typedef bool
 (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                      JS::Handle<JSPropertyDescriptor> desc,
                      JS::ObjectOpResult& result);
 typedef bool
 (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
 typedef bool
-(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
+(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
                   JS::MutableHandleValue vp);
 typedef bool
 (* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
                   JS::HandleValue receiver, JS::ObjectOpResult& result);
 typedef bool
 (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                      JS::MutableHandle<JSPropertyDescriptor> desc);
 typedef bool
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -288,17 +288,17 @@ class JS_FRIEND_API(BaseProxyHandler)
     /*
      * These standard internal methods are implemented, as a convenience, so
      * that ProxyHandler subclasses don't have to provide every single method.
      *
      * The base-class implementations work by calling getPropertyDescriptor().
      * They do not follow any standard. When in doubt, override them.
      */
     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const;
-    virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                      HandleId id, MutableHandleValue vp) const;
     virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const;
 
     /*
      * [[Call]] and [[Construct]] are standard internal methods but according
      * to the spec, they are not present on every object.
      *
@@ -389,17 +389,17 @@ class JS_FRIEND_API(DirectProxyHandler) 
                               ObjectOpResult& result) const override;
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
                                        bool* succeeded) const override;
     virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
                                    ObjectOpResult& result) const override;
     virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
                      bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                      HandleId id, MutableHandleValue vp) const override;
     virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const override;
     virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1788,17 +1788,17 @@ TypedObject::obj_hasProperty(JSContext* 
         *foundp = false;
         return true;
     }
 
     return HasProperty(cx, proto, id, foundp);
 }
 
 bool
-TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                              HandleId id, MutableHandleValue vp)
 {
     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
 
     // Dispatch elements to obj_getElement:
     uint32_t index;
     if (IdIsIndex(id, &index))
         return obj_getElement(cx, obj, receiver, index, vp);
@@ -1845,17 +1845,17 @@ TypedObject::obj_getProperty(JSContext* 
         vp.setUndefined();
         return true;
     }
 
     return GetProperty(cx, proto, receiver, id, vp);
 }
 
 bool
-TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleObject receiver,
+TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
                             uint32_t index, MutableHandleValue vp)
 {
     MOZ_ASSERT(obj->is<TypedObject>());
     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
     Rooted<TypeDescr*> descr(cx, &typedObj->typeDescr());
 
     switch (descr->kind()) {
       case type::Scalar:
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -524,20 +524,20 @@ class TypedObject : public JSObject
                                    MutableHandleShape propp);
 
     static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
                                    Handle<JSPropertyDescriptor> desc,
                                    ObjectOpResult& result);
 
     static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
 
-    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                                 HandleId id, MutableHandleValue vp);
 
-    static bool obj_getElement(JSContext* cx, HandleObject obj, HandleObject receiver,
+    static bool obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
                                uint32_t index, MutableHandleValue vp);
 
     static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                                 HandleValue receiver, ObjectOpResult& result);
 
     static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -6864,18 +6864,19 @@ ICGetProp_DOMProxyShadowed::Compiler::ge
     RootedShape shape(cx, proxy_->maybeShape());
     return New<ICGetProp_DOMProxyShadowed>(cx, space, getStubCode(), firstMonitorStub_, shape,
                                            proxy_->handler(), name_, pcOffset_);
 }
 
 static bool
 ProxyGet(JSContext* cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
 {
+    RootedValue receiver(cx, ObjectValue(*proxy));
     RootedId id(cx, NameToId(name));
-    return Proxy::get(cx, proxy, proxy, id, vp);
+    return Proxy::get(cx, proxy, receiver, id, vp);
 }
 
 typedef bool (*ProxyGetFn)(JSContext* cx, HandleObject proxy, HandlePropertyName name,
                            MutableHandleValue vp);
 static const VMFunction ProxyGetInfo = FunctionInfo<ProxyGetFn>(ProxyGet);
 
 bool
 ICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler& masm)
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1535,69 +1535,80 @@ static void
 PushObjectOpResult(MacroAssembler& masm)
 {
     static_assert(sizeof(ObjectOpResult) == sizeof(uintptr_t),
                   "ObjectOpResult size must match size reserved by masm.Push() here");
     masm.Push(ImmWord(ObjectOpResult::Uninitialized));
 }
 
 static bool
+ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+{
+    RootedValue receiver(cx, ObjectValue(*proxy));
+    return Proxy::get(cx, proxy, receiver, id, vp);
+}
+
+static bool
+ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+{
+    RootedValue receiver(cx, ObjectValue(*proxy));
+    return Proxy::callProp(cx, proxy, receiver, id, vp);
+}
+
+static bool
 EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
                  PropertyName* name, LiveRegisterSet liveRegs, Register object,
                  TypedOrValueRegister output, jsbytecode* pc, void* returnAddr)
 {
     MOZ_ASSERT(output.hasValue());
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
 
     // Remaining registers should be free, but we need to use |object| still
     // so leave it alone.
     AllocatableRegisterSet regSet(RegisterSet::All());
     regSet.take(AnyRegister(object));
 
-    // Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
-    //            MutableHandleValue vp)
+    // ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id,
+    //                  MutableHandleValue vp)
     Register argJSContextReg = regSet.takeAnyGeneral();
     Register argProxyReg     = regSet.takeAnyGeneral();
     Register argIdReg        = regSet.takeAnyGeneral();
     Register argVpReg        = regSet.takeAnyGeneral();
 
     Register scratch         = regSet.takeAnyGeneral();
 
-    void* getFunction = JSOp(*pc) == JSOP_CALLPROP                      ?
-                            JS_FUNC_TO_DATA_PTR(void*, Proxy::callProp) :
-                            JS_FUNC_TO_DATA_PTR(void*, Proxy::get);
+    void* getFunction = JSOp(*pc) == JSOP_CALLPROP                        ?
+                            JS_FUNC_TO_DATA_PTR(void*, ProxyCallProperty) :
+                            JS_FUNC_TO_DATA_PTR(void*, ProxyGetProperty);
 
     // Push stubCode for marking.
     attacher.pushStubCodePointer(masm);
 
     // Push args on stack first so we can take pointers to make handles.
     masm.Push(UndefinedValue());
     masm.moveStackPtrTo(argVpReg);
 
     RootedId propId(cx, AtomToId(name));
     masm.Push(propId, scratch);
     masm.moveStackPtrTo(argIdReg);
 
-    // Pushing object and receiver.  Both are the same, so Handle to one is equivalent to
-    // handle to other.
-    masm.Push(object);
+    // Push the proxy. Also used as receiver.
     masm.Push(object);
     masm.moveStackPtrTo(argProxyReg);
 
     masm.loadJSContext(argJSContextReg);
 
     if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
         return false;
     masm.enterFakeExitFrame(IonOOLProxyExitFrameLayoutToken);
 
     // Make the call.
     masm.setupUnalignedABICall(scratch);
     masm.passABIArg(argJSContextReg);
     masm.passABIArg(argProxyReg);
-    masm.passABIArg(argProxyReg);
     masm.passABIArg(argIdReg);
     masm.passABIArg(argVpReg);
     masm.callWithABI(getFunction);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     // Load the outparam vp[0] into output register(s).
@@ -2279,19 +2290,17 @@ EmitCallProxySet(JSContext* cx, MacroAss
     masm.Push(value);
     masm.moveStackPtrTo(argValueReg);
 
     masm.move32(Imm32(strict), argStrictReg);
 
     masm.Push(propId, scratch);
     masm.moveStackPtrTo(argIdReg);
 
-    // Pushing object and receiver.  Both are the same, so Handle to one is equivalent to
-    // handle to other.
-    masm.Push(object);
+    // Push object.
     masm.Push(object);
     masm.moveStackPtrTo(argProxyReg);
 
     masm.loadJSContext(argJSContextReg);
 
     if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
         return false;
     masm.enterFakeExitFrame(IonOOLProxyExitFrameLayoutToken);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1396,17 +1396,16 @@ MarkJitExitFrame(JSTracer* trc, const Ji
     }
 
     if (frame.isExitFrameLayout<IonOOLProxyExitFrameLayout>()) {
         IonOOLProxyExitFrameLayout* oolproxy = frame.exitFrame()->as<IonOOLProxyExitFrameLayout>();
         TraceRoot(trc, oolproxy->stubCode(), "ion-ool-proxy-code");
         TraceRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
         TraceRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
         TraceRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
-        TraceRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
         return;
     }
 
     if (frame.isExitFrameLayout<IonDOMExitFrameLayout>()) {
         IonDOMExitFrameLayout* dom = frame.exitFrame()->as<IonDOMExitFrameLayout>();
         TraceRoot(trc, dom->thisObjAddress(), "ion-dom-args");
         if (dom->isMethodFrame()) {
             IonDOMMethodExitFrameLayout* method =
--- a/js/src/jit/JitFrames.h
+++ b/js/src/jit/JitFrames.h
@@ -694,32 +694,29 @@ class IonOOLSetterOpExitFrameLayout : pu
         return offsetof(IonOOLSetterOpExitFrameLayout, result_);
     }
 
     static size_t Size() {
         return sizeof(IonOOLSetterOpExitFrameLayout);
     }
 };
 
-// Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
-//            MutableHandleValue vp)
+// ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+// ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
 // ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
 //                  bool strict)
 class IonOOLProxyExitFrameLayout
 {
   protected: // only to silence a clang warning about unused private fields
     ExitFooterFrame footer_;
     ExitFrameLayout exit_;
 
     // The proxy object.
     JSObject* proxy_;
 
-    // Object for HandleObject
-    JSObject* receiver_;
-
     // id for HandleId
     jsid id_;
 
     // space for MutableHandleValue result
     // use two uint32_t so compiler doesn't align.
     uint32_t vp0_;
     uint32_t vp1_;
 
@@ -741,19 +738,16 @@ class IonOOLProxyExitFrameLayout
         return &stubCode_;
     }
     inline Value* vp() {
         return reinterpret_cast<Value*>(&vp0_);
     }
     inline jsid* id() {
         return &id_;
     }
-    inline JSObject** receiver() {
-        return &receiver_;
-    }
     inline JSObject** proxy() {
         return &proxy_;
     }
 };
 
 class IonDOMExitFrameLayout
 {
   protected: // only to silence a clang warning about unused private fields
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -372,17 +372,17 @@ proxy_LookupProperty(JSContext* cx, JS::
                     JS::MutableHandle<Shape*> propp);
 extern JS_FRIEND_API(bool)
 proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                      JS::Handle<JSPropertyDescriptor> desc,
                      JS::ObjectOpResult& result);
 extern JS_FRIEND_API(bool)
 proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
 extern JS_FRIEND_API(bool)
-proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
+proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
                   JS::MutableHandleValue vp);
 extern JS_FRIEND_API(bool)
 proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp,
                   JS::HandleValue receiver, JS::ObjectOpResult& result);
 extern JS_FRIEND_API(bool)
 proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                                JS::MutableHandle<JSPropertyDescriptor> desc);
 extern JS_FRIEND_API(bool)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -814,41 +814,76 @@ HasProperty(JSContext* cx, HandleObject 
  * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
  * such property exists.
  *
  * Typically obj == receiver; if obj != receiver then the caller is most likely
  * a proxy using GetProperty to finish a property get that started out as
  * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
  */
 inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
             MutableHandleValue vp);
 
 inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
+GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, PropertyName* name,
             MutableHandleValue vp)
 {
     RootedId id(cx, NameToId(name));
     return GetProperty(cx, obj, receiver, id, vp);
 }
 
 inline bool
+GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+            MutableHandleValue vp)
+{
+    RootedValue receiverValue(cx, ObjectValue(*receiver));
+    return GetProperty(cx, obj, receiverValue, id, vp);
+}
+
+inline bool
+GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
+            MutableHandleValue vp)
+{
+    RootedValue receiverValue(cx, ObjectValue(*receiver));
+    return GetProperty(cx, obj, receiverValue, name, vp);
+}
+
+inline bool
+GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
+           MutableHandleValue vp);
+
+inline bool
 GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
            MutableHandleValue vp);
 
 inline bool
-GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp);
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
+{
+    return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), id, vp);
+}
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
+{
+    return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
+}
 
 inline bool
 GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, PropertyName* name, Value* vp)
 {
-    return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
+    return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), name, vp);
 }
 
 inline bool
+GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
+
+inline bool
 GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);
 
 /*
  * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
  *
  * The `receiver` argument has to do with how [[Set]] interacts with the
  * prototype chain and proxies. It's hard to explain and ES6 doesn't really
  * try. Long story short, if you just want bog-standard assignment, pass
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -175,37 +175,51 @@ js::IsExtensible(ExclusiveContext* cx, H
 inline bool
 js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found)
 {
     RootedId id(cx, NameToId(name));
     return HasProperty(cx, obj, id, found);
 }
 
 inline bool
-js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
+js::GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
                MutableHandleValue vp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return GetProperty(cx, obj, receiver, id, vp);
 }
 
 inline bool
-js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
+js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
+               MutableHandleValue vp)
+{
+    RootedValue receiverValue(cx, ObjectValue(*receiver));
+    return GetElement(cx, obj, receiverValue, index, vp);
+}
+
+inline bool
+js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp)
 {
     if (obj->getOps()->getProperty)
         return false;
 
     if (index > JSID_INT_MAX)
         return false;
     return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
 }
 
 inline bool
+js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
+{
+    return GetElementNoGC(cx, obj, ObjectValue(*receiver), index, vp);
+}
+
+inline bool
 js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
 {
     MarkTypePropertyNonData(cx, obj, id);
     if (DeletePropertyOp op = obj->getOps()->deleteProperty)
         return op(cx, obj, id, result);
     return NativeDeleteProperty(cx, obj.as<NativeObject>(), id, result);
 }
 
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -128,17 +128,17 @@ class JS_FRIEND_API(CrossCompartmentWrap
                               ObjectOpResult& result) const override;
 
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
                                        bool* succeeded) const override;
     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
                                    ObjectOpResult& result) const override;
     virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
     virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
+    virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
                      HandleId id, MutableHandleValue vp) const override;
     virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const override;
     virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
@@ -186,17 +186,17 @@ class JS_FRIEND_API(OpaqueCrossCompartme
                               ObjectOpResult& result) const override;
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
                                        bool* succeeded) const override;
     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
                                    ObjectOpResult& result) const override;
     virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
     virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
                      bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
+    virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
                      HandleId id, MutableHandleValue vp) const override;
     virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const override;
     virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -60,17 +60,17 @@ BaseProxyHandler::hasOwn(JSContext* cx, 
     Rooted<PropertyDescriptor> desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
         return false;
     *bp = !!desc.object();
     return true;
 }
 
 bool
-BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                       HandleId id, MutableHandleValue vp) const
 {
     assertEnteredPolicy(cx, proxy, id, GET);
 
     Rooted<PropertyDescriptor> desc(cx);
     if (!getPropertyDescriptor(cx, proxy, id, &desc))
         return false;
     if (!desc.object()) {
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -148,20 +148,20 @@ CrossCompartmentWrapper::hasOwn(JSContex
 {
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::hasOwn(cx, wrapper, id, bp),
            NOTHING);
 }
 
 bool
-CrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
+CrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
                              HandleId id, MutableHandleValue vp) const
 {
-    RootedObject receiverCopy(cx, receiver);
+    RootedValue receiverCopy(cx, receiver);
     {
         AutoCompartment call(cx, wrappedObject(wrapper));
         if (!cx->compartment()->wrap(cx, &receiverCopy))
             return false;
 
         if (!Wrapper::get(cx, wrapper, receiverCopy, id, vp))
             return false;
     }
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -212,17 +212,17 @@ bool
 DirectProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
 {
     assertEnteredPolicy(cx, proxy, id, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return HasOwnProperty(cx, target, id, bp);
 }
 
 bool
-DirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+DirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                         HandleId id, MutableHandleValue vp) const
 {
     assertEnteredPolicy(cx, proxy, id, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetProperty(cx, target, receiver, id, vp);
 }
 
 bool
--- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
+++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
@@ -90,17 +90,17 @@ OpaqueCrossCompartmentWrapper::isExtensi
 bool
 OpaqueCrossCompartmentWrapper::has(JSContext* cx, HandleObject wrapper, HandleId id,
                                    bool* bp) const
 {
     return BaseProxyHandler::has(cx, wrapper, id, bp);
 }
 
 bool
-OpaqueCrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
+OpaqueCrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
                                    HandleId id, MutableHandleValue vp) const
 {
     return BaseProxyHandler::get(cx, wrapper, receiver, id, vp);
 }
 
 bool
 OpaqueCrossCompartmentWrapper::set(JSContext* cx, HandleObject wrapper, HandleId id,
                                    HandleValue v, HandleValue receiver,
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -266,29 +266,29 @@ OuterizeValue(JSContext* cx, HandleValue
     if (v.isObject()) {
         RootedObject obj(cx, &v.toObject());
         return ObjectValue(*GetOuterObject(cx, obj));
     }
     return v;
 }
 
 bool
-Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver_, HandleId id,
+Proxy::get(JSContext* cx, HandleObject proxy, HandleValue receiver_, HandleId id,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
     vp.setUndefined(); // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
 
     // Outerize the receiver. Proxy handlers shouldn't have to know about
     // the Window/WindowProxy distinction.
-    RootedObject receiver(cx, GetOuterObject(cx, receiver_));
+    RootedValue receiver(cx, OuterizeValue(cx, receiver_));
 
     if (handler->hasPrototype()) {
         bool own;
         if (!handler->hasOwn(cx, proxy, id, &own))
             return false;
         if (!own) {
             RootedObject proto(cx);
             if (!GetPrototype(cx, proxy, &proto))
@@ -298,17 +298,17 @@ Proxy::get(JSContext* cx, HandleObject p
             return GetProperty(cx, proto, receiver, id, vp);
         }
     }
 
     return handler->get(cx, proxy, receiver, id, vp);
 }
 
 bool
-Proxy::callProp(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+Proxy::callProp(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
                 MutableHandleValue vp)
 {
     // The inline caches need an access point for JSOP_CALLPROP sites that accounts
     // for the possibility of __noSuchMethod__
     if (!Proxy::get(cx, proxy, receiver, id, vp))
         return false;
 
 #if JS_HAS_NO_SUCH_METHOD
@@ -589,17 +589,17 @@ js::proxy_DefineProperty(JSContext* cx, 
 
 bool
 js::proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp)
 {
     return Proxy::has(cx, obj, id, foundp);
 }
 
 bool
-js::proxy_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+js::proxy_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
                       MutableHandleValue vp)
 {
     return Proxy::get(cx, obj, receiver, id, vp);
 }
 
 bool
 js::proxy_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                       HandleValue receiver, ObjectOpResult& result)
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -35,17 +35,17 @@ class Proxy
     static bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp);
     static bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible);
     static bool preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result);
     static bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop);
     static bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
                              ObjectOpResult& result);
     static bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded);
     static bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
-    static bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+    static bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
                     MutableHandleValue vp);
     static bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
                     HandleValue receiver, ObjectOpResult& result);
     static bool call(JSContext* cx, HandleObject proxy, const CallArgs& args);
     static bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args);
 
     /* SpiderMonkey extensions. */
     static bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
@@ -67,15 +67,16 @@ class Proxy
     static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id);
 
     static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end,
                             ElementAdder* adder);
 
     static void trace(JSTracer* trc, JSObject* obj);
 
     /* IC entry path for handling __noSuchMethod__ on access. */
-    static bool callProp(JSContext* cx, HandleObject proxy, HandleObject reveiver, HandleId id,
+    static bool callProp(JSContext* cx, HandleObject proxy, HandleValue reveiver, HandleId id,
                          MutableHandleValue vp);
+
 };
 
 } /* namespace js */
 
 #endif /* proxy_Proxy_h */
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -841,17 +841,17 @@ ScriptedDirectProxyHandler::has(JSContex
 
     // step 12
     *bp = success;
     return true;
 }
 
 // ES6 (22 May, 2014) 9.5.8 Proxy.[[GetP]](P, Receiver)
 bool
-ScriptedDirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+ScriptedDirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                                 HandleId id, MutableHandleValue vp) const
 {
     // step 2
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
 
     // step 3
     if (!handler) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
@@ -872,17 +872,17 @@ ScriptedDirectProxyHandler::get(JSContex
 
     // step 8-9
     RootedValue value(cx);
     if (!IdToStringOrSymbol(cx, id, &value))
         return false;
     Value argv[] = {
         ObjectOrNullValue(target),
         value,
-        ObjectOrNullValue(receiver)
+        receiver
     };
     RootedValue trapResult(cx);
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
 
     // step 10-11
     Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -39,17 +39,17 @@ class ScriptedDirectProxyHandler : publi
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
                                        bool* succeeded) const override;
 
     virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
                                    ObjectOpResult& result) const override;
     virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
 
     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
                      MutableHandleValue vp) const override;
     virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const override;
     virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override {
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -280,25 +280,25 @@ ScriptedIndirectProxyHandler::hasOwn(JSC
         return false;
     if (!IsCallable(fval))
         return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
     return Trap1(cx, handler, fval, id, &value) &&
            ValueToBool(value, bp);
 }
 
 bool
-ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
+ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                                   HandleId id, MutableHandleValue vp) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue idv(cx);
     if (!IdToStringOrSymbol(cx, id, &idv))
         return false;
     JS::AutoValueArray<2> argv(cx);
-    argv[0].setObjectOrNull(receiver);
+    argv[0].set(receiver);
     argv[1].set(idv);
     RootedValue fval(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))
         return false;
     if (!IsCallable(fval))
         return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
     return Trap(cx, handler, fval, 2, argv.begin(), vp);
 }
--- a/js/src/proxy/ScriptedIndirectProxyHandler.h
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.h
@@ -30,17 +30,17 @@ class ScriptedIndirectProxyHandler : pub
     virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                          ObjectOpResult& result) const override;
     virtual bool enumerate(JSContext* cx, HandleObject proxy,
                            MutableHandleObject objp) const override;
     virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
                                    ObjectOpResult& result) const override;
     virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
                      MutableHandleValue vp) const override;
     virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
                      HandleValue receiver, ObjectOpResult& result) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -448,64 +448,65 @@ GetObjectElementOperation(JSContext* cx,
     }
 #endif
 
     assertSameCompartmentDebugOnly(cx, res);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
-GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver,
+GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver_,
                              HandleValue key, MutableHandleValue res)
 {
     MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
 
     // FIXME: We shouldn't be boxing here or exposing the boxed object as
     //        receiver anywhere below (bug 603201).
-    RootedObject boxed(cx, ToObjectFromStack(cx, receiver));
+    RootedObject boxed(cx, ToObjectFromStack(cx, receiver_));
     if (!boxed)
         return false;
+    RootedValue receiver(cx, ObjectValue(*boxed));
 
     do {
         uint32_t index;
         if (IsDefinitelyIndex(key, &index)) {
-            if (GetElementNoGC(cx, boxed, boxed, index, res.address()))
+            if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
                 break;
 
-            if (!GetElement(cx, boxed, boxed, index, res))
+            if (!GetElement(cx, boxed, receiver, index, res))
                 return false;
             break;
         }
 
         if (IsSymbolOrSymbolWrapper(key)) {
             RootedId id(cx, SYMBOL_TO_JSID(ToSymbolPrimitive(key)));
-            if (!GetProperty(cx, boxed, boxed, id, res))
+            if (!GetProperty(cx, boxed, receiver, id, res))
                 return false;
             break;
         }
 
         if (JSAtom* name = ToAtom<NoGC>(cx, key)) {
             if (name->isIndex(&index)) {
-                if (GetElementNoGC(cx, boxed, boxed, index, res.address()))
+                if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
                     break;
             } else {
-                if (GetPropertyNoGC(cx, boxed, boxed, name->asPropertyName(), res.address()))
+                if (GetPropertyNoGC(cx, boxed, receiver, name->asPropertyName(), res.address()))
                     break;
             }
         }
 
         JSAtom* name = ToAtom<CanGC>(cx, key);
         if (!name)
             return false;
 
         if (name->isIndex(&index)) {
-            if (!GetElement(cx, boxed, boxed, index, res))
+            if (!GetElement(cx, boxed, receiver, index, res))
                 return false;
         } else {
-            if (!GetProperty(cx, boxed, boxed, name->asPropertyName(), res))
+            if (!GetProperty(cx, boxed, receiver, name->asPropertyName(), res))
                 return false;
         }
     } while (false);
 
     // Note: we don't call a __noSuchMethod__ hook when |this| was primitive.
 
     assertSameCompartmentDebugOnly(cx, res);
     return true;
@@ -550,18 +551,20 @@ GetElementOperation(JSContext* cx, JSOp 
             str = cx->staticStrings().getUnitStringForElement(cx, str, index);
             if (!str)
                 return false;
             res.setString(str);
             return true;
         }
     }
 
-    if (lref.isPrimitive())
-        return GetPrimitiveElementOperation(cx, op, lref, rref, res);
+    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);
 }
 
 static MOZ_ALWAYS_INLINE JSString*
 TypeOfOperation(const Value& v, JSRuntime* rt)
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -250,17 +250,19 @@ GetPropertyOperation(JSContext* cx, Inte
     if (op == JSOP_CALLPROP) {
         // The __noSuchMethod__ code in CallProperty requires non-aliasing
         // v and vp arguments.
         RootedValue v(cx, lval);
         return CallProperty(cx, v, name, vp);
     }
 
     MOZ_ASSERT(op == JSOP_GETPROP || op == JSOP_LENGTH);
-    return GetProperty(cx, lval, name, vp);
+    // Copy lval, because it might alias vp.
+    RootedValue v(cx, lval);
+    return GetProperty(cx, v, name, vp);
 }
 
 static inline bool
 GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHandleValue vp)
 {
     JSObject* obj = fp->scopeChain();
     PropertyName* name = fp->script()->getName(pc);
 
@@ -911,25 +913,25 @@ js::InternalConstructWithProvidedThis(JS
     if (!InternalConstruct(cx, args))
         return false;
 
     rval.set(args.rval());
     return true;
 }
 
 bool
-js::InvokeGetter(JSContext* cx, JSObject* obj, Value fval, MutableHandleValue rval)
+js::InvokeGetter(JSContext* cx, const Value& thisv, Value fval, MutableHandleValue rval)
 {
     /*
      * Invoke could result in another try to get or set the same id again, see
      * bug 355497.
      */
     JS_CHECK_RECURSION(cx, return false);
 
-    return Invoke(cx, ObjectValue(*obj), fval, 0, nullptr, rval);
+    return Invoke(cx, thisv, fval, 0, nullptr, rval);
 }
 
 bool
 js::InvokeSetter(JSContext* cx, const Value& thisv, Value fval, HandleValue v)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     RootedValue ignored(cx);
@@ -4185,27 +4187,29 @@ js::GetProperty(JSContext* cx, HandleVal
             proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
         } else if (v.isBoolean()) {
             proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
         } else {
             MOZ_ASSERT(v.isSymbol());
             proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
         }
         if (!proto)
-             return false;
+            return false;
 
         if (GetPropertyPure(cx, proto, NameToId(name), vp.address()))
             return true;
     }
 
     RootedObject obj(cx, ToObjectFromStack(cx, v));
     if (!obj)
         return false;
 
-    return GetProperty(cx, obj, obj, name, vp);
+    // Bug 603201: Pass primitive receiver here.
+    RootedValue receiver(cx, ObjectValue(*obj));
+    return GetProperty(cx, obj, receiver, name, vp);
 }
 
 bool
 js::CallProperty(JSContext* cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
 {
     // __noSuchMethod__ code below depends on this.
     MOZ_ASSERT(v.address() != vp.address());
 
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -75,17 +75,17 @@ extern bool
 Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc, const Value* argv,
        MutableHandleValue rval);
 
 /*
  * These helpers take care of the infinite-recursion check necessary for
  * getter/setter calls.
  */
 extern bool
-InvokeGetter(JSContext* cx, JSObject* obj, Value fval, MutableHandleValue rval);
+InvokeGetter(JSContext* cx, const Value& thisv, Value fval, MutableHandleValue rval);
 
 extern bool
 InvokeSetter(JSContext* cx, const Value& thisv, Value fval, HandleValue v);
 
 // ES6 7.3.13 Construct(F, argumentsList, newTarget).  All parameters are
 // required, hopefully forcing callers to be careful not to (say) blindly pass
 // callee as |newTarget| when a different value should have been passed.
 //
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1189,17 +1189,17 @@ static bool IsAccessorDescriptor(unsigne
 static bool IsDataDescriptor(unsigned attrs) {
     MOZ_ASSERT((attrs & (JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY)) == 0);
     return !IsAccessorDescriptor(attrs);
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 GetExistingProperty(JSContext* cx,
-                    typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
+                    typename MaybeRooted<Value, allowGC>::HandleType receiver,
                     typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                     typename MaybeRooted<Shape*, allowGC>::HandleType shape,
                     typename MaybeRooted<Value, allowGC>::MutableHandleType vp);
 
 static bool
 GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
                          HandleShape shape, MutableHandleValue vp)
 {
@@ -1208,17 +1208,18 @@ GetExistingPropertyValue(ExclusiveContex
         return true;
     }
     if (!cx->shouldBeJSContext())
         return false;
 
     MOZ_ASSERT(shape->propid() == id);
     MOZ_ASSERT(obj->contains(cx, shape));
 
-    return GetExistingProperty<CanGC>(cx->asJSContext(), obj, obj, shape, vp);
+    RootedValue receiver(cx, ObjectValue(*obj));
+    return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp);
 }
 
 /*
  * If ES6 draft rev 37 9.1.6.3 ValidateAndApplyPropertyDescriptor step 4 would
  * return early, because desc is redundant with an existing own property obj[id],
  * then set *redundant = true and return true.
  */
 static bool
@@ -1639,17 +1640,17 @@ js::NativeHasProperty(JSContext* cx, Han
         pobj = &proto->as<NativeObject>();
     }
 }
 
 
 /*** [[Get]] *************************************************************************************/
 
 static inline bool
-CallGetter(JSContext* cx, HandleObject obj, HandleObject receiver, HandleShape shape,
+CallGetter(JSContext* cx, HandleObject obj, HandleValue receiver, HandleShape shape,
            MutableHandleValue vp)
 {
     MOZ_ASSERT(!shape->hasDefaultGetter());
 
     if (shape->hasGetterValue()) {
         Value fval = shape->getterValue();
         return InvokeGetter(cx, receiver, fval, vp);
     }
@@ -1657,17 +1658,17 @@ CallGetter(JSContext* cx, HandleObject o
     // In contrast to normal getters JSGetterOps always want the holder.
     RootedId id(cx, shape->propid());
     return CallJSGetterOp(cx, shape->getterOp(), obj, id, vp);
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 GetExistingProperty(JSContext* cx,
-                    typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
+                    typename MaybeRooted<Value, allowGC>::HandleType receiver,
                     typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                     typename MaybeRooted<Shape*, allowGC>::HandleType shape,
                     typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
     if (shape->hasSlot()) {
         vp.set(obj->getSlot(shape->slot()));
         MOZ_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) &&
                       !obj->isSingleton() &&
@@ -1696,17 +1697,17 @@ GetExistingProperty(JSContext* cx,
         }
     }
 
     if (!allowGC)
         return false;
 
     if (!CallGetter(cx,
                     MaybeRooted<JSObject*, allowGC>::toHandle(obj),
-                    MaybeRooted<JSObject*, allowGC>::toHandle(receiver),
+                    MaybeRooted<Value, allowGC>::toHandle(receiver),
                     MaybeRooted<Shape*, allowGC>::toHandle(shape),
                     MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
     {
         return false;
     }
 
     // Ancient nonstandard extension: via the JSAPI it's possible to create a
     // data property that has both a slot and a getter. In that case, copy the
@@ -1716,17 +1717,18 @@ GetExistingProperty(JSContext* cx,
 
     return true;
 }
 
 bool
 js::NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObject obj,
                               HandleShape shape, MutableHandleValue vp)
 {
-    return GetExistingProperty<CanGC>(cx, receiver, obj, shape, vp);
+    RootedValue receiverValue(cx, ObjectValue(*receiver));
+    return GetExistingProperty<CanGC>(cx, receiverValue, obj, shape, vp);
 }
 
 /*
  * Given pc pointing after a property accessing bytecode, return true if the
  * access is "property-detecting" -- that is, if we shouldn't warn about it
  * even if no such property is found and strict warnings are enabled.
  */
 static bool
@@ -1779,17 +1781,17 @@ enum IsNameLookup { NotNameLookup = fals
  *     out if that's what's happening and throw a ReferenceError if so.
  *
  * 3.  We also emit an optional warning for this. (It's not super useful on the
  *     web, as there are too many false positives, but anecdotally useful in
  *     Gecko code.)
  */
 static bool
 GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
-                       HandleObject receiver, IsNameLookup nameLookup, MutableHandleValue vp)
+                       HandleValue receiver, IsNameLookup nameLookup, MutableHandleValue vp)
 {
     vp.setUndefined();
 
     // Non-standard extension: Call the getProperty hook. If it sets vp to a
     // value other than undefined, we're done. If not, fall through to the
     // warning/error checks below.
     if (JSGetterOp getProperty = obj->getClass()->getProperty) {
         if (!CallJSGetterOp(cx, getProperty, obj, id, vp))
@@ -1844,24 +1846,24 @@ GetNonexistentProperty(JSContext* cx, Ha
     // Ok, bad undefined property reference: whine about it.
     RootedValue val(cx, IdToValue(id));
     return ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, JSDVG_IGNORE_STACK, val,
                                     nullptr, nullptr, nullptr);
 }
 
 /* The NoGC version of GetNonexistentProperty, present only to make types line up. */
 bool
-GetNonexistentProperty(JSContext* cx, NativeObject* obj, jsid id, JSObject* receiver,
+GetNonexistentProperty(JSContext* cx, NativeObject* obj, jsid id, Value& receiver,
                        IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
 {
     return false;
 }
 
 static inline bool
-GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject receiver,
+GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue receiver,
                        IsNameLookup nameLookup, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     if (nameLookup) {
         // When nameLookup is true, GetProperty implements ES6 rev 34 (2015 Feb
         // 20) 8.1.1.2.6 GetBindingValue, with step 3 (the call to HasProperty)
         // and step 6 (the call to Get) fused so that only a single lookup is
         // needed.
@@ -1876,30 +1878,30 @@ GeneralizedGetProperty(JSContext* cx, Ha
         if (!found)
             return ReportIsNotDefined(cx, id);
     }
 
     return GetProperty(cx, obj, receiver, id, vp);
 }
 
 static inline bool
-GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, JSObject* receiver,
+GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, const Value& receiver,
                        IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
 {
     JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
     if (nameLookup)
         return false;
     return GetPropertyNoGC(cx, obj, receiver, id, vp.address());
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 NativeGetPropertyInline(JSContext* cx,
                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
-                        typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
+                        typename MaybeRooted<Value, allowGC>::HandleType receiver,
                         typename MaybeRooted<jsid, allowGC>::HandleType id,
                         IsNameLookup nameLookup,
                         typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
     typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
     typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
 
     // This loop isn't explicit in the spec algorithm. See the comment on step
@@ -1943,35 +1945,36 @@ NativeGetPropertyInline(JSContext* cx,
         if (proto->getOps()->getProperty)
             return GeneralizedGetProperty(cx, proto, id, receiver, nameLookup, vp);
 
         pobj = &proto->as<NativeObject>();
     }
 }
 
 bool
-js::NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+js::NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
                       MutableHandleValue vp)
 {
     return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, NotNameLookup, vp);
 }
 
 bool
-js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, JSObject* receiver, jsid id, Value* vp)
+js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp)
 {
     AutoAssertNoException noexc(cx);
     return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, NotNameLookup, vp);
 }
 
 bool
 js::GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
+    RootedValue receiver(cx, ObjectValue(*obj));
     if (obj->getOps()->getProperty)
-        return GeneralizedGetProperty(cx, obj, id, obj, NameLookup, vp);
-    return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), obj, id, NameLookup, vp);
+        return GeneralizedGetProperty(cx, obj, id, receiver, NameLookup, vp);
+    return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), receiver, id, NameLookup, vp);
 }
 
 
 /*** [[Set]] *************************************************************************************/
 
 static bool
 MaybeReportUndeclaredVarAssignment(JSContext* cx, JSString* propname)
 {
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1283,36 +1283,38 @@ extern bool
 NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
                      HandleValue value, JSGetterOp getter, JSSetterOp setter,
                      unsigned attrs);
 
 extern bool
 NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp);
 
 extern bool
-NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
                   MutableHandleValue vp);
 
 extern bool
-NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, JSObject* receiver, jsid id, Value* vp);
+NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp);
 
 extern bool
-NativeGetElement(JSContext* cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
+NativeGetElement(JSContext* cx, HandleNativeObject obj, HandleValue receiver, uint32_t index,
                  MutableHandleValue vp);
 
 inline bool
 NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleValue vp)
 {
-    return NativeGetProperty(cx, obj, obj, id, vp);
+    RootedValue receiver(cx, ObjectValue(*obj));
+    return NativeGetProperty(cx, obj, receiver, id, vp);
 }
 
 inline bool
 NativeGetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, MutableHandleValue vp)
 {
-    return NativeGetElement(cx, obj, obj, index, vp);
+    RootedValue receiver(cx, ObjectValue(*obj));
+    return NativeGetElement(cx, obj, receiver, index, vp);
 }
 
 bool
 SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                       HandleValue receiver, ObjectOpResult& result);
 
 bool
 SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
@@ -1404,26 +1406,26 @@ inline bool
 js::HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
 {
     if (HasPropertyOp op = obj->getOps()->hasProperty)
         return op(cx, obj, id, foundp);
     return NativeHasProperty(cx, obj.as<NativeObject>(), id, foundp);
 }
 
 inline bool
-js::GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+js::GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
                 MutableHandleValue vp)
 {
     if (GetPropertyOp op = obj->getOps()->getProperty)
         return op(cx, obj, receiver, id, vp);
     return NativeGetProperty(cx, obj.as<NativeObject>(), receiver, id, vp);
 }
 
 inline bool
-js::GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
+js::GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp)
 {
     if (obj->getOps()->getProperty)
         return false;
     return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
 }
 
 inline bool
 js::SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -499,21 +499,24 @@ with_DefineProperty(JSContext* cx, Handl
 static bool
 with_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return HasProperty(cx, actual, id, foundp);
 }
 
 static bool
-with_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+with_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
                  MutableHandleValue vp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
-    return GetProperty(cx, actual, actual, id, vp);
+    RootedValue actualReceiver(cx, receiver);
+    if (receiver.isObject() && &receiver.toObject() == obj)
+        actualReceiver.setObject(*actual);
+    return GetProperty(cx, actual, actualReceiver, id, vp);
 }
 
 static bool
 with_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                  HandleValue receiver, ObjectOpResult& result)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     RootedValue actualReceiver(cx, receiver);
@@ -977,17 +980,17 @@ uninitialized_LookupProperty(JSContext* 
 static bool
 uninitialized_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
-uninitialized_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
+uninitialized_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
                           MutableHandleValue vp)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
 uninitialized_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
@@ -1619,17 +1622,17 @@ class DebugScopeProxy : public BaseProxy
                                  "Debugger scope");
             return false;
         }
 
         vp.setObject(*argsObj);
         return true;
     }
 
-    bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+    bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
              MutableHandleValue vp) const override
     {
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
         if (isMissingArguments(cx, id, *scope))
             return getMissingArguments(cx, *scope, vp);
 
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -775,30 +775,32 @@ UnboxedPlainObject::obj_hasProperty(JSCo
         *foundp = false;
         return true;
     }
 
     return HasProperty(cx, proto, id, foundp);
 }
 
 /* static */ bool
-UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                                     HandleId id, MutableHandleValue vp)
 {
     const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
 
     if (const UnboxedLayout::Property* property = layout.lookup(id)) {
         vp.set(obj->as<UnboxedPlainObject>().getValue(*property));
         return true;
     }
 
     if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
         if (expando->containsShapeOrElement(cx, id)) {
             RootedObject nexpando(cx, expando);
-            RootedObject nreceiver(cx, (obj == receiver) ? expando : receiver.get());
+            RootedValue nreceiver(cx, receiver);
+            if (receiver.isObject() && &receiver.toObject() == obj)
+                nreceiver.setObject(*expando);
             return GetProperty(cx, nexpando, nreceiver, id, vp);
         }
     }
 
     RootedObject proto(cx, obj->getProto());
     if (!proto) {
         vp.setUndefined();
         return true;
@@ -1477,17 +1479,17 @@ UnboxedArrayObject::obj_hasProperty(JSCo
         *foundp = false;
         return true;
     }
 
     return HasProperty(cx, proto, id, foundp);
 }
 
 /* static */ bool
-UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                                     HandleId id, MutableHandleValue vp)
 {
     if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
         if (JSID_IS_INT(id))
             vp.set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
         else
             vp.set(Int32Value(obj->as<UnboxedArrayObject>().length()));
         return true;
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -245,17 +245,17 @@ class UnboxedPlainObject : public JSObje
                                    MutableHandleShape propp);
 
     static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
                                    Handle<JSPropertyDescriptor> desc,
                                    ObjectOpResult& result);
 
     static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
 
-    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                                 HandleId id, MutableHandleValue vp);
 
     static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                                 HandleValue receiver, ObjectOpResult& result);
 
     static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);
 
@@ -381,17 +381,17 @@ class UnboxedArrayObject : public JSObje
                                    MutableHandleShape propp);
 
     static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
                                    Handle<JSPropertyDescriptor> desc,
                                    ObjectOpResult& result);
 
     static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
 
-    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
+    static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
                                 HandleId id, MutableHandleValue vp);
 
     static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                                 HandleValue receiver, ObjectOpResult& result);
 
     static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);