bool
BaselineInspector::maybeInfoForPropertyOp(jsbytecode *pc,
                                          ShapeVector &nativeShapes,
                                          ObjectGroupVector &unboxedGroups,
                                          ObjectGroupVector &convertUnboxedGroups)
{
    // Return lists of native shapes and unboxed objects seen by the baseline
    // IC for the current op. Empty lists indicate no shapes/types 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(nativeShapes.empty());
    MOZ_ASSERT(unboxedGroups.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()) {
        Shape *shape = nullptr;
        ObjectGroup *group = nullptr;
        if (stub->isGetProp_Native()) {
            shape = stub->toGetProp_Native()->shape();
        } else if (stub->isSetProp_Native()) {
            shape = stub->toSetProp_Native()->shape();
        } else if (stub->isGetProp_Unboxed()) {
            group = stub->toGetProp_Unboxed()->group();
        } else if (stub->isSetProp_Unboxed()) {
            group = stub->toSetProp_Unboxed()->group();
        } else {
            nativeShapes.clear();
            unboxedGroups.clear();
            return true;
        }

        if (group && group->unboxedLayout().nativeGroup()) {
            if (!VectorAppendNoDuplicate(convertUnboxedGroups, group))
                return false;
            shape = group->unboxedLayout().nativeShape();
            group = nullptr;
        }

        if (shape) {
            if (!VectorAppendNoDuplicate(nativeShapes, shape))
                return false;
        } else {
            if (!VectorAppendNoDuplicate(unboxedGroups, group))
                return false;
        }

        stub = stub->next();
    }

    if (stub->isGetProp_Fallback()) {
        if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) {
            nativeShapes.clear();
            unboxedGroups.clear();
        }
    } else {
        if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) {
            nativeShapes.clear();
            unboxedGroups.clear();
        }
    }

    // Don't inline if there are more than 5 shapes/groups.
    if (nativeShapes.length() + unboxedGroups.length() > 5) {
        nativeShapes.clear();
        unboxedGroups.clear();
    }

    return true;
}