MCompare::CompareType BaselineInspector::expectedCompareType(jsbytecode *pc) { ICStub *first = monomorphicStub(pc), *second = NULL; if (!first && !dimorphicStub(pc, &first, &second)) return MCompare::Compare_Unknown; if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) return MCompare::Compare_Int32; if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) { ICCompare_NumberWithUndefined *coerce = first->isCompare_NumberWithUndefined() ? first->toCompare_NumberWithUndefined() : (second && second->isCompare_NumberWithUndefined()) ? second->toCompare_NumberWithUndefined() : NULL; if (coerce) { return coerce->lhsIsUndefined() ? MCompare::Compare_DoubleMaybeCoerceLHS : MCompare::Compare_DoubleMaybeCoerceRHS; } return MCompare::Compare_Double; } return MCompare::Compare_Unknown; }
MIRType BaselineInspector::expectedResultType(jsbytecode *pc) { // Look at the IC entries for this op to guess what type it will produce, // returning MIRType_None otherwise. ICStub *stub = monomorphicStub(pc); if (!stub) return MIRType_None; switch (stub->kind()) { case ICStub::BinaryArith_Int32: if (stub->toBinaryArith_Int32()->allowDouble()) return MIRType_Double; return MIRType_Int32; case ICStub::BinaryArith_BooleanWithInt32: case ICStub::UnaryArith_Int32: case ICStub::BinaryArith_DoubleWithInt32: return MIRType_Int32; case ICStub::BinaryArith_Double: case ICStub::UnaryArith_Double: return MIRType_Double; case ICStub::BinaryArith_StringConcat: case ICStub::BinaryArith_StringObjectConcat: return MIRType_String; default: return MIRType_None; } }
bool BaselineInspector::isOptimizableConstStringSplit(jsbytecode* pc, JSString** strOut, JSString** sepOut, ArrayObject** objOut) { if (!hasICScript()) { return false; } const ICEntry& entry = icEntryFromPC(pc); // If ConstStringSplit stub is attached, must have only one stub attached. if (entry.fallbackStub()->numOptimizedStubs() != 1) { return false; } ICStub* stub = entry.firstStub(); if (stub->kind() != ICStub::Call_ConstStringSplit) { return false; } *strOut = stub->toCall_ConstStringSplit()->expectedStr(); *sepOut = stub->toCall_ConstStringSplit()->expectedSep(); *objOut = stub->toCall_ConstStringSplit()->templateObject(); return true; }
JSObject * BaselineInspector::getTemplateObject(jsbytecode *pc) { if (!hasBaselineScript()) return nullptr; const ICEntry &entry = icEntryFromPC(pc); for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) { switch (stub->kind()) { case ICStub::NewArray_Fallback: return stub->toNewArray_Fallback()->templateObject(); case ICStub::NewObject_Fallback: return stub->toNewObject_Fallback()->templateObject(); case ICStub::Rest_Fallback: return stub->toRest_Fallback()->templateObject(); case ICStub::Call_Scripted: if (JSObject *obj = stub->toCall_Scripted()->templateObject()) return obj; break; default: break; } } return nullptr; }
MIRType BaselineInspector::expectedResultType(jsbytecode* pc) { // Look at the IC entries for this op to guess what type it will produce, // returning MIRType::None otherwise. Note that IonBuilder may call this // for bytecode ops that are unreachable and don't have a Baseline IC, see // comment in monomorphicStub. ICStub* stub = monomorphicStub(pc); if (!stub) return MIRType::None; switch (stub->kind()) { case ICStub::BinaryArith_Int32: if (stub->toBinaryArith_Int32()->allowDouble()) return MIRType::Double; return MIRType::Int32; case ICStub::BinaryArith_BooleanWithInt32: case ICStub::UnaryArith_Int32: case ICStub::BinaryArith_DoubleWithInt32: return MIRType::Int32; case ICStub::BinaryArith_Double: case ICStub::UnaryArith_Double: return MIRType::Double; case ICStub::BinaryArith_StringConcat: case ICStub::BinaryArith_StringObjectConcat: return MIRType::String; default: return MIRType::None; } }
MCompare::CompareType BaselineInspector::expectedCompareType(jsbytecode* pc) { ICStub* first = monomorphicStub(pc); ICStub* second = nullptr; if (!first && !dimorphicStub(pc, &first, &second)) return MCompare::Compare_Unknown; if (ICStub* fallback = second ? second->next() : first->next()) { MOZ_ASSERT(fallback->isFallback()); if (fallback->toCompare_Fallback()->hadUnoptimizableAccess()) return MCompare::Compare_Unknown; } if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) { ICCompare_Int32WithBoolean* coerce = first->isCompare_Int32WithBoolean() ? first->toCompare_Int32WithBoolean() : ((second && second->isCompare_Int32WithBoolean()) ? second->toCompare_Int32WithBoolean() : nullptr); if (coerce) { return coerce->lhsIsInt32() ? MCompare::Compare_Int32MaybeCoerceRHS : MCompare::Compare_Int32MaybeCoerceLHS; } return MCompare::Compare_Int32; } if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) { ICCompare_NumberWithUndefined* coerce = first->isCompare_NumberWithUndefined() ? first->toCompare_NumberWithUndefined() : (second && second->isCompare_NumberWithUndefined()) ? second->toCompare_NumberWithUndefined() : nullptr; if (coerce) { return coerce->lhsIsUndefined() ? MCompare::Compare_DoubleMaybeCoerceLHS : MCompare::Compare_DoubleMaybeCoerceRHS; } return MCompare::Compare_Double; } return MCompare::Compare_Unknown; }
ObjectGroup* BaselineInspector::getTemplateObjectGroup(jsbytecode* pc) { if (!hasICScript()) { return nullptr; } const ICEntry& entry = icEntryFromPC(pc); for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { switch (stub->kind()) { case ICStub::NewArray_Fallback: return stub->toNewArray_Fallback()->templateGroup(); default: break; } } return nullptr; }
MIRType BaselineInspector::expectedResultType(jsbytecode* pc) { // Look at the IC entries for this op to guess what type it will produce, // returning MIRType::None otherwise. Note that IonBuilder may call this // for bytecode ops that are unreachable and don't have a Baseline IC, see // comment in monomorphicStub. ICStub* stub = monomorphicStub(pc); if (!stub) { return MIRType::None; } switch (stub->kind()) { case ICStub::CacheIR_Regular: return ParseCacheIRStub(stub); default: return MIRType::None; } }
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; }
bool BaselineInspector::isOptimizableCallStringSplit(jsbytecode* pc, JSString** stringOut, JSString** stringArg, JSObject** objOut) { if (!hasBaselineScript()) return false; const ICEntry& entry = icEntryFromPC(pc); // If StringSplit stub is attached, must have only one stub attached. if (entry.fallbackStub()->numOptimizedStubs() != 1) return false; ICStub* stub = entry.firstStub(); if (stub->kind() != ICStub::Call_StringSplit) return false; *stringOut = stub->toCall_StringSplit()->expectedThis(); *stringArg = stub->toCall_StringSplit()->expectedArg(); *objOut = stub->toCall_StringSplit()->templateObject(); 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::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_ArrayLength: case ICStub::GetProp_UnboxedArrayLength: case ICStub::GetProp_Native: case ICStub::GetProp_NativeDoesNotExist: case ICStub::GetProp_NativePrototype: case ICStub::GetProp_Unboxed: case ICStub::GetProp_TypedObject: case ICStub::GetProp_CallScripted: case ICStub::GetProp_CallNative: case ICStub::GetProp_CallDOMProxyNative: case ICStub::GetProp_CallDOMProxyWithGenerationNative: case ICStub::GetProp_DOMProxyShadowed: case ICStub::GetElem_NativeSlot: case ICStub::GetElem_NativePrototypeSlot: case ICStub::GetElem_NativePrototypeCallNative: case ICStub::GetElem_NativePrototypeCallScripted: 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; 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; }