Bug 923765 - Account for __noSuchMethod__ in proxy stubs in GetPropertyIC. (r=djvj)
authorEric Faust <efaustbmo@gmail.com>
Thu, 17 Oct 2013 18:13:43 -0700
changeset 165947 e9b3eac5b6744e2147db5f67cec634bbfea83b9a
parent 165946 c0aa048f0c2f247101740708d50c70a5e464e77e
child 165948 7349a4fc4d5801341c564c00bbd902e18f91d402
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs923765
milestone27.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 923765 - Account for __noSuchMethod__ in proxy stubs in GetPropertyIC. (r=djvj)
js/src/jit/IonCaches.cpp
js/src/jsproxy.cpp
js/src/jsproxy.h
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1299,20 +1299,21 @@ GetPropertyIC::tryAttachTypedArrayLength
     RepatchStubAppender attacher(*this);
     GenerateTypedArrayLength(cx, masm, attacher, obj, object(), output());
 
     JS_ASSERT(!hasTypedArrayLengthStub_);
     hasTypedArrayLengthStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array length");
 }
 
+
 static bool
 EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                  PropertyName *name, RegisterSet liveRegs, Register object,
-                 TypedOrValueRegister output, void *returnAddr)
+                 TypedOrValueRegister output, jsbytecode *pc, void *returnAddr)
 {
     JS_ASSERT(output.hasValue());
     // saveLive()
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
 
     // Remaining registers should be free, but we need to use |object| still
     // so leave it alone.
     RegisterSet regSet(RegisterSet::All());
@@ -1323,16 +1324,19 @@ EmitCallProxyGet(JSContext *cx, MacroAss
     Register argJSContextReg = regSet.takeGeneral();
     Register argProxyReg     = regSet.takeGeneral();
     Register argIdReg        = regSet.takeGeneral();
     Register argVpReg        = regSet.takeGeneral();
 
     Register scratch         = regSet.takeGeneral();
 
     DebugOnly<uint32_t> initialStack = masm.framePushed();
+    void *getFunction = JSOp(*pc) == JSOP_CALLPROP                      ?
+                            JS_FUNC_TO_DATA_PTR(void *, Proxy::callProp) :
+                            JS_FUNC_TO_DATA_PTR(void *, Proxy::get);
 
     // Push stubCode for marking.
     attacher.pushStubCodePointer(masm);
 
     // Push args on stack first so we can take pointers to make handles.
     masm.Push(UndefinedValue());
     masm.movePtr(StackPointer, argVpReg);
 
@@ -1354,17 +1358,17 @@ EmitCallProxyGet(JSContext *cx, MacroAss
 
     // Make the call.
     masm.setupUnalignedABICall(5, scratch);
     masm.passABIArg(argJSContextReg);
     masm.passABIArg(argProxyReg);
     masm.passABIArg(argProxyReg);
     masm.passABIArg(argIdReg);
     masm.passABIArg(argVpReg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::get));
+    masm.callWithABI(getFunction);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     // Load the outparam vp[0] into output register(s).
     masm.loadValue(
         Address(StackPointer, IonOOLProxyExitFrameLayout::offsetOfResult()),
         JSReturnOperand);
@@ -1409,18 +1413,21 @@ GetPropertyIC::tryAttachDOMProxyShadowed
                                    Address(object(), JSObject::offsetOfShape()),
                                    ImmGCPtr(obj->lastProperty()),
                                    &failures);
 
     // Make sure object is a DOMProxy
     GenerateDOMProxyChecks(cx, masm, obj, name(), object(), &failures,
                            /*skipExpandoCheck=*/true);
 
-    if (!EmitCallProxyGet(cx, masm, attacher, name(), liveRegs_, object(), output(), returnAddr))
+    if (!EmitCallProxyGet(cx, masm, attacher, name(), liveRegs_, object(), output(),
+                          pc(), returnAddr))
+    {
         return false;
+    }
 
     // Success.
     attacher.jumpRejoin(masm);
 
     // Failure.
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
@@ -1509,17 +1516,17 @@ GetPropertyIC::tryAttachDOMProxyUnshadow
                 return false;
             }
         }
     } else {
         // Property was not found on the prototype chain. Deoptimize down to
         // proxy get call
         JS_ASSERT(!idempotent());
         if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(),
-                              returnAddr))
+                              pc(), returnAddr))
         {
             return false;
         }
     }
 
     attacher.jumpRejoin(masm);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
@@ -1598,18 +1605,21 @@ GetPropertyIC::tryAttachGenericProxy(JSC
 
     GenerateProxyClassGuards(masm, object(), scratchReg, &failures);
 
     // Ensure that the incoming object is not a DOM proxy, so that we can get to
     // the specialized stubs
     masm.branchTestProxyHandlerFamily(Assembler::Equal, object(), scratchReg,
                                       GetDOMProxyHandlerFamily(), &failures);
 
-    if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(), returnAddr))
+    if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(),
+                          pc(), returnAddr))
+    {
         return false;
+    }
 
     attacher.jumpRejoin(masm);
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     JS_ASSERT(!hasGenericProxyStub_);
     hasGenericProxyStub_ = true;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2481,16 +2481,36 @@ Proxy::get(JSContext *cx, HandleObject p
             return false;
     }
     if (own)
         return handler->get(cx, proxy, receiver, id, vp);
     INVOKE_ON_PROTOTYPE(cx, handler, proxy, JSObject::getGeneric(cx, proto, receiver, id, vp));
 }
 
 bool
+Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject 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
+    if (JS_UNLIKELY(vp.isPrimitive())) {
+        if (!OnUnknownMethod(cx, proxy, IdToValue(id), vp))
+            return false;
+    }
+#endif
+
+    return true;
+}
+
+
+bool
 Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
                            MutableHandleValue vp, bool *present)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -270,16 +270,20 @@ class Proxy
     static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
     static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
     static const char *className(JSContext *cx, HandleObject proxy);
     static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
     static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
     static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
     static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
 
+    /* IC entry path for handling __noSuchMethod__ on access. */
+    static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
+                         MutableHandleValue vp);
+
     static JSObject * const LazyProto;
 };
 
 // Use these in places where you don't want to #include vm/ProxyObject.h.
 extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr;
 extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr;
 extern JS_FRIEND_DATA(const js::Class* const) OuterWindowProxyClassPtr;