diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index 1b639d6b10..6ecbd707be 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -663,10 +663,155 @@ GlobalShapeForGetPropFunction(ICStub* stub) if (nstub->isOwnGetter()) return nullptr; - const HeapReceiverGuard& guard = nstub->receiverGuard(); - if (Shape* shape = guard.shape()) { - if (shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL) - return shape; + *receiver = ReceiverGuard(); + + if (reader.matchOp(CacheOp::GuardShape, objId)) { + // The first case. + receiver->shape = stubInfo->getStubField(stub, reader.stubOffset()); + return true; + } + + if (!reader.matchOp(CacheOp::GuardGroup, objId)) + return false; + receiver->group = stubInfo->getStubField(stub, reader.stubOffset()); + + if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) { + // Second case, just a group guard. + reader.matchOp(CacheOp::GuardNoUnboxedExpando, objId); + return true; + } + + // Third case. + ObjOperandId expandoId = reader.objOperandId(); + if (!reader.matchOp(CacheOp::GuardShape, expandoId)) + return false; + + receiver->shape = stubInfo->getStubField(stub, reader.stubOffset()); + return true; +} + +static bool +AddCacheIRGlobalGetter(ICCacheIR_Monitored* stub, bool innerized, + JSObject** holder_, Shape** holderShape_, + JSFunction** commonGetter, Shape** globalShape_, bool* isOwnProperty, + BaselineInspector::ReceiverVector& receivers, + BaselineInspector::ObjectGroupVector& convertUnboxedGroups, + JSScript* script) +{ + // We are matching on the IR generated by tryAttachGlobalNameGetter: + // + // GuardShape objId + // globalId = LoadEnclosingEnvironment objId + // GuardShape globalId + // > + // + // CallNativeGetterResult globalId + + CacheIRReader reader(stub->stubInfo()); + + ObjOperandId objId = ObjOperandId(0); + if (!reader.matchOp(CacheOp::GuardShape, objId)) + return false; + Shape* globalLexicalShape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); + + if (!reader.matchOp(CacheOp::LoadEnclosingEnvironment, objId)) + return false; + ObjOperandId globalId = reader.objOperandId(); + + if (!reader.matchOp(CacheOp::GuardShape, globalId)) + return false; + Shape* globalShape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); + MOZ_ASSERT(globalShape->getObjectClass()->flags & JSCLASS_IS_GLOBAL); + + JSObject* holder = &script->global(); + Shape* holderShape = globalShape; + if (reader.matchOp(CacheOp::LoadObject)) { + ObjOperandId holderId = reader.objOperandId(); + holder = stub->stubInfo()->getStubField(stub, reader.stubOffset()).get(); + + if (!reader.matchOp(CacheOp::GuardShape, holderId)) + return false; + holderShape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); + } + + // This guard will always fail, try the next stub. + if (holder->as().lastProperty() != holderShape) + return true; + + if (!reader.matchOp(CacheOp::CallNativeGetterResult, globalId)) + return false; + size_t offset = reader.stubOffset(); + JSFunction* getter = + &stub->stubInfo()->getStubField(stub, offset)->as(); + + ReceiverGuard receiver; + receiver.shape = globalLexicalShape; + if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) + return false; + + if (!*commonGetter) { + *holder_ = holder; + *holderShape_ = holderShape; + *commonGetter = getter; + *globalShape_ = globalShape; + + // This is always false, because the getters never live on the globalLexical. + *isOwnProperty = false; + } else if (*isOwnProperty || holderShape != *holderShape_ || globalShape != *globalShape_) { + return false; + } else { + MOZ_ASSERT(*commonGetter == getter); + } + + return true; +} + +static bool +AddCacheIRGetPropFunction(ICCacheIR_Monitored* stub, bool innerized, + JSObject** holder, Shape** holderShape, + JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty, + BaselineInspector::ReceiverVector& receivers, + BaselineInspector::ObjectGroupVector& convertUnboxedGroups, + JSScript* script) +{ + // We match either an own getter: + // + // GuardIsObject objId + // [..WindowProxy innerization..] + // + // Call(Scripted|Native)GetterResult objId + // + // Or a getter on the prototype: + // + // GuardIsObject objId + // [..WindowProxy innerization..] + // + // LoadObject holderId + // GuardShape holderId + // Call(Scripted|Native)GetterResult objId + // + // If |innerized| is true, we replaced a WindowProxy with the Window + // object and we're only interested in Baseline getter stubs that performed + // the same optimization. This means we expect the following ops for the + // [..WindowProxy innerization..] above: + // + // GuardClass objId WindowProxy + // objId = LoadObject + + CacheIRReader reader(stub->stubInfo()); + + ObjOperandId objId = ObjOperandId(0); + if (!reader.matchOp(CacheOp::GuardIsObject, objId)) { + return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape, commonGetter, + globalShape, isOwnProperty, receivers, convertUnboxedGroups, + script); + } + + if (innerized) { + if (!reader.matchOp(CacheOp::GuardClass, objId) || + reader.guardClassKind() != GuardClassKind::WindowProxy) + { + return false; } } else if (stub->isGetProp_CallNativeGlobal()) { ICGetProp_CallNativeGlobal* nstub = stub->toGetProp_CallNativeGlobal();