bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, ObjectGroupVector& convertUnboxedGroups) { // Return a list of the receivers seen by the baseline IC for the current // op. Empty lists indicate no receivers are known, or there was an // uncacheable access. convertUnboxedGroups is used for unboxed object // groups which have been seen, but have had instances converted to native // objects and should be eagerly converted by Ion. MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(convertUnboxedGroups.empty()); if (!hasBaselineScript()) return true; MOZ_ASSERT(isValidPC(pc)); const ICEntry& entry = icEntryFromPC(pc); ICStub* stub = entry.firstStub(); while (stub->next()) { ReceiverGuard receiver; if (stub->isCacheIR_Monitored()) { if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver) && !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), &receiver)) { receivers.clear(); return true; } } else if (stub->isCacheIR_Updated()) { if (!GetCacheIRReceiverForNativeSetSlot(stub->toCacheIR_Updated(), &receiver) && !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Updated(), &receiver)) { receivers.clear(); return true; } } else { receivers.clear(); return true; } if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) return false; stub = stub->next(); } if (stub->isGetProp_Fallback()) { if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) receivers.clear(); } else { if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) receivers.clear(); } // Don't inline if there are more than 5 receivers. if (receivers.length() > 5) receivers.clear(); return true; }
MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) { if (!hasICScript()) { return MIRType::Value; } const ICEntry& entry = icEntryFromPC(pc); MIRType type = MIRType::None; for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { MIRType stubType = MIRType::None; if (stub->isCacheIR_Monitored()) { stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored()); if (stubType == MIRType::Value) { return MIRType::Value; } } else if (stub->isGetElem_Fallback() || stub->isGetProp_Fallback()) { // If we have an unoptimizable access, don't try to optimize. if (stub->toFallbackStub()->state().hasFailures()) { return MIRType::Value; } } else { MOZ_CRASH("Unexpected stub"); } if (type != MIRType::None) { if (type != stubType) { return MIRType::Value; } } else { type = stubType; } } return (type == MIRType::None) ? MIRType::Value : type; }
bool BaselineInspector::megamorphicGetterSetterFunction(jsbytecode* pc, bool isGetter, JSFunction** getterOrSetter) { if (!hasBaselineScript()) return false; *getterOrSetter = nullptr; const ICEntry& entry = icEntryFromPC(pc); for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isCacheIR_Monitored()) { MOZ_ASSERT(isGetter); JSFunction* getter = GetMegamorphicGetterSetterFunction(stub, stub->toCacheIR_Monitored()->stubInfo(), isGetter); if (!getter || (*getterOrSetter && *getterOrSetter != getter)) return false; *getterOrSetter = getter; continue; } if (stub->isCacheIR_Updated()) { MOZ_ASSERT(!isGetter); JSFunction* setter = GetMegamorphicGetterSetterFunction(stub, stub->toCacheIR_Updated()->stubInfo(), isGetter); if (!setter || (*getterOrSetter && *getterOrSetter != setter)) return false; *getterOrSetter = setter; continue; } if (stub->isGetProp_Fallback()) { if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) return false; if (stub->toGetProp_Fallback()->state().mode() != ICState::Mode::Megamorphic) return false; continue; } if (stub->isSetProp_Fallback()) { if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) return false; if (stub->toSetProp_Fallback()->state().mode() != ICState::Mode::Megamorphic) return false; continue; } return false; } if (!*getterOrSetter) return false; return true; }
bool BaselineInspector::maybeInfoForProtoReadSlot( jsbytecode* pc, ReceiverVector& receivers, ObjectGroupVector& convertUnboxedGroups, JSObject** holder) { // This is like maybeInfoForPropertyOp, but for when the property exists on // the prototype. MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(convertUnboxedGroups.empty()); MOZ_ASSERT(!*holder); if (!hasICScript()) { return true; } MOZ_ASSERT(isValidPC(pc)); const ICEntry& entry = icEntryFromPC(pc); ICStub* stub = entry.firstStub(); while (stub->next()) { ReceiverGuard receiver; if (stub->isCacheIR_Monitored()) { if (!GetCacheIRReceiverForProtoReadSlot(stub->toCacheIR_Monitored(), &receiver, holder)) { receivers.clear(); return true; } } else { receivers.clear(); return true; } if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) { return false; } stub = stub->next(); } if (stub->toFallbackStub()->state().hasFailures()) { receivers.clear(); } // Don't inline if there are more than 5 receivers. if (receivers.length() > 5) { receivers.clear(); } MOZ_ASSERT_IF(!receivers.empty(), *holder); return true; }
bool BaselineInspector::commonGetPropFunction(jsbytecode* pc, bool innerized, JSObject** holder, Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty, ReceiverVector& receivers, ObjectGroupVector& convertUnboxedGroups) { if (!hasBaselineScript()) return false; MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(convertUnboxedGroups.empty()); *globalShape = nullptr; *commonGetter = nullptr; const ICEntry& entry = icEntryFromPC(pc); for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isCacheIR_Monitored()) { if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), innerized, holder, holderShape, commonGetter, globalShape, isOwnProperty, receivers, convertUnboxedGroups, script)) { return false; } } else if (stub->isGetProp_Fallback()) { // If we have an unoptimizable access, don't try to optimize. if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) return false; } else if (stub->isGetName_Fallback()) { if (stub->toGetName_Fallback()->hadUnoptimizableAccess()) return false; } else { return false; } } if (!*commonGetter) return false; MOZ_ASSERT(*isOwnProperty == !*holder); MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty())); return true; }
MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) { if (!hasBaselineScript()) return MIRType::Value; const ICEntry& entry = icEntryFromPC(pc); MIRType type = MIRType::None; for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { MIRType stubType; switch (stub->kind()) { case ICStub::GetProp_Fallback: if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) return MIRType::Value; continue; case ICStub::GetElem_Fallback: if (stub->toGetElem_Fallback()->hadUnoptimizableAccess()) return MIRType::Value; continue; case ICStub::CacheIR_Monitored: stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored()); if (stubType == MIRType::Value) return MIRType::Value; break; default: MOZ_CRASH("Unexpected stub"); } if (type != MIRType::None) { if (type != stubType) return MIRType::Value; } else { type = stubType; } } return (type == MIRType::None) ? MIRType::Value : type; }
MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) { if (!hasBaselineScript()) return MIRType::Value; const ICEntry& entry = icEntryFromPC(pc); MIRType type = MIRType::None; for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { MIRType stubType; switch (stub->kind()) { case ICStub::GetProp_Fallback: if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) return MIRType::Value; continue; case ICStub::GetElem_Fallback: if (stub->toGetElem_Fallback()->hadUnoptimizableAccess()) return MIRType::Value; continue; case ICStub::GetProp_Generic: return MIRType::Value; case ICStub::GetProp_ArgumentsLength: case ICStub::GetElem_Arguments: // Either an object or magic arguments. return MIRType::Value; case ICStub::GetProp_CallScripted: case ICStub::GetProp_CallNative: case ICStub::GetProp_CallDOMProxyNative: case ICStub::GetProp_CallDOMProxyWithGenerationNative: case ICStub::GetProp_DOMProxyShadowed: case ICStub::GetElem_NativeSlotName: case ICStub::GetElem_NativeSlotSymbol: case ICStub::GetElem_NativePrototypeSlotName: case ICStub::GetElem_NativePrototypeSlotSymbol: case ICStub::GetElem_NativePrototypeCallNativeName: case ICStub::GetElem_NativePrototypeCallNativeSymbol: case ICStub::GetElem_NativePrototypeCallScriptedName: case ICStub::GetElem_NativePrototypeCallScriptedSymbol: case ICStub::GetElem_UnboxedPropertyName: case ICStub::GetElem_String: case ICStub::GetElem_Dense: case ICStub::GetElem_TypedArray: case ICStub::GetElem_UnboxedArray: stubType = MIRType::Object; break; case ICStub::GetProp_Primitive: stubType = MIRTypeFromValueType(stub->toGetProp_Primitive()->primitiveType()); break; case ICStub::GetProp_StringLength: stubType = MIRType::String; break; case ICStub::CacheIR_Monitored: stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored()); if (stubType == MIRType::Value) return MIRType::Value; break; default: MOZ_CRASH("Unexpected stub"); } if (type != MIRType::None) { if (type != stubType) return MIRType::Value; } else { type = stubType; } } return (type == MIRType::None) ? MIRType::Value : type; }