diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 922ba79da9c..da84883782f 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1570,11 +1570,8 @@ GetPropertyIC::tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject // Ensure that the incoming object is not a DOM proxy, so that we can get to // the specialized stubs - Address handlerAddr(object(), ProxyObject::offsetOfHandler()); - masm.loadPrivate(handlerAddr, scratchReg); - Address familyAddr(scratchReg, BaseProxyHandler::offsetOfFamily()); - masm.branchPtr(Assembler::Equal, familyAddr, ImmWord(GetDOMProxyHandlerFamily()), - &failures); + masm.branchTestProxyHandlerFamily(Assembler::Equal, object(), scratchReg, + GetDOMProxyHandlerFamily(), &failures); if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(), returnAddr)) return false; @@ -2160,6 +2157,11 @@ SetPropertyIC::attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAdd GenerateProxyClassGuards(masm, object(), scratch, &proxyFailures, &proxySuccess); + // Remove the DOM proxies. They'll take care of themselves so this stub doesn't + // catch too much. + masm.branchTestProxyHandlerFamily(Assembler::Equal, object(), scratch, + GetDOMProxyHandlerFamily(), &proxyFailures); + masm.bind(&proxyFailures); masm.pop(scratch); // Unify the point of failure to allow for later DOM proxy handling. @@ -2187,6 +2189,44 @@ SetPropertyIC::attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAdd return linkAndAttachStub(cx, masm, attacher, ion, "generic proxy set"); } +bool +SetPropertyIC::attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj, + void *returnAddr) +{ + JS_ASSERT(IsCacheableDOMProxy(obj)); + + Label failures; + MacroAssembler masm(cx); + RepatchStubAppender attacher(*this); + + masm.setFramePushed(ion->frameSize()); + + // Guard on the shape of the object. + masm.branchPtr(Assembler::NotEqual, + Address(object(), JSObject::offsetOfShape()), + ImmGCPtr(obj->lastProperty()), &failures); + + // Make sure object is a DOMProxy + GenerateDOMProxyChecks(cx, masm, obj, name(), object(), &failures, + /*skipExpandoCheck=*/true); + + RootedId propId(cx, AtomToId(name())); + if (!EmitCallProxySet(cx, masm, attacher, propId, liveRegs_, object(), + value(), returnAddr, strict())) + { + return false; + } + + // Success. + attacher.jumpRejoin(masm); + + // Failure. + masm.bind(&failures); + attacher.jumpNextStub(masm); + + return linkAndAttachStub(cx, masm, attacher, ion, "DOM proxy shadowed set"); +} + bool SetPropertyIC::attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj, HandleObject holder, HandleShape shape, @@ -2565,12 +2605,23 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj, bool inlinable = cache.canAttachStub() && !obj->watched(); bool addedSetterStub = false; if (inlinable) { - if (!addedSetterStub && obj->is() && - !cache.hasGenericProxyStub()) - { - if (!cache.attachGenericProxy(cx, ion, returnAddr)) - return false; - addedSetterStub = true; + if (!addedSetterStub && obj->is()) { + if (IsCacheableDOMProxy(obj)) { + DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id); + if (shadows == ShadowCheckFailed) + return false; + if (shadows == Shadows) { + if (!cache.attachDOMProxyShadowed(cx, ion, obj, returnAddr)) + return false; + addedSetterStub = true; + } + } + + if (!addedSetterStub && !cache.hasGenericProxyStub()) { + if (!cache.attachGenericProxy(cx, ion, returnAddr)) + return false; + addedSetterStub = true; + } } RootedShape shape(cx); if (!addedSetterStub && IsPropertySetInlineable(cx, cache, obj, id, &shape)) { diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index 83512ec52c4..2d355c4f378 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -696,6 +696,8 @@ class SetPropertyIC : public RepatchIonCache bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape, HandleShape newshape, HandleShape propshape); bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr); + bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj, + void *returnAddr); static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value); diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index c94d912629e..c656ec470e6 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -189,6 +189,13 @@ class MacroAssembler : public MacroAssemblerSpecific void branchTestObjShape(Condition cond, Register obj, Register shape, Label *label) { branchPtr(cond, Address(obj, JSObject::offsetOfShape()), shape, label); } + void branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch, + void *handlerp, Label *label) { + Address handlerAddr(proxy, ProxyObject::offsetOfHandler()); + loadPrivate(handlerAddr, scratch); + Address familyAddr(scratch, BaseProxyHandler::offsetOfFamily()); + branchPtr(cond, familyAddr, ImmWord(handlerp), label); + } template Condition testMIRType(Condition cond, const Value &val, MIRType type) {