/** * During the join process, there might be cycle. It means the ECR <code> * root</code> might be set to <code>freshType</code>. The type-union should take care of it -- * union <code>freshType</code> to <code>unionType</code>. In particular, <code>freshType</code> * is an object type, while <code> * unionType</code> is a struct type, then <code>unionType</code> should be collapsed before union * with <code>freshType</code>. * * @param root * @param unionType * @param freshType * @return unified type */ private ValueType resolveType(ECR root, ValueType unionType, ValueType freshType) { Preconditions.checkArgument(!unionType.isLambda()); Preconditions.checkArgument(!freshType.isLambda()); Pair<ValueType, ValueType> pair = swap(unionType, freshType); ValueType t1 = pair.fst(), t2 = pair.snd(); if (t1.isSimple() && t2.isStruct()) { Collection<ECR> elems = t2.asStruct().getFieldMap().asMapOfRanges().values(); ValueType resType = t1; for (ECR elem : elems) { ECR elemLoc = getLoc(elem); ValueType elemLocType = getType(elemLoc); Parent parent = elemLocType.getParent().removeECR(root); elemLocType.setParent(parent); if (elemLocType.isStruct()) { elemLocType = collapseStruct(elemLoc, elemLocType.asStruct()); } union(root, elemLoc); resType = unify(resType, elemLocType); } return resType; } return unify(t1, t2); }
/** * Check if one of <code>e1</code> or <code>e2</code> is a struct, and the other is either object * or simple, collapse the one with struct type * * @param e1 * @param e2 */ private void checkStructCollapse(ECR e1, ECR e2) { ValueType t1 = getType(e1); ValueType t2 = getType(e2); if (t2.isStruct() && t1.isSimple()) { collapseStruct(e2, t2.asStruct()); return; } if (t1.isStruct() && t2.isSimple()) { collapseStruct(e1, t1.asStruct()); return; } return; }
void ensureSimple(ECR e) { ValueType type = getType(e); switch (type.getKind()) { case BOTTOM: { ValueType simType = ValueType.simple(createBottomLocFunc(), Size.getBot(), Parent.getBottom()); setType(e, simType); return; } case BLANK: { BlankType blankType = type.asBlank(); ValueType simType = ValueType.simple(createBottomLocFunc(), blankType.getSize(), blankType.getParent()); setType(e, simType); return; } case SIMPLE: { return; } case STRUCT: { collapseStruct(e, type.asStruct()); return; } default: // lambda throw new IllegalArgumentException("Invalid type " + type.getKind()); } }
void clearPointerArithmetic() { if (ptrAriJoins.isEmpty()) return; for (Entry<Pair<ECR, Long>, Pair<ECR, Long>> cell : ptrAriJoins.entrySet()) { ECR resECR = findRoot(cell.getKey().fst()); final ECR origECR = findRoot(cell.getValue().fst()); long shift = cell.getValue().snd(); if (shift >= 0) { // TODO: could do more precise analysis here. collapse(origECR, resECR); continue; } ValueType origType = getType(origECR); Parent parent = origType.getParent(); if (parent.getECRs().isEmpty()) { // TODO: could do more precise analysis here. collapse(origECR, resECR); continue; } for (ECR parentECR : parent.getECRs()) { ValueType parentType = getType(parentECR); if (!parentType.isStruct()) { IOUtils.errPrinter().pln("WARNING: non-struct parent"); join(parentECR, origECR); continue; } Map<Range<Long>, ECR> fieldMap = parentType.asStruct().getFieldMap().asMapOfRanges(); Entry<Range<Long>, ECR> fieldRange = Iterables.find( fieldMap.entrySet(), new Predicate<Entry<Range<Long>, ECR>>() { @Override public boolean apply(Entry<Range<Long>, ECR> input) { return origECR.equals(getLoc(input.getValue())); } }); long low = fieldRange.getKey().lowerEndpoint() + shift; Size parentSize = parentType.getSize(); long size = cell.getKey().snd(); if (low == 0 && (parentSize.isBottom() || parentSize.isNumber() && parentSize.getValue() == size)) { join(parentECR, resECR); continue; } collapse(origECR, resECR); } } }
void collapse(ECR e1, ECR e2) { ECR root = join(e1, e2); // Parent is stored at the points-to loc of Parent parent = getType(root).getParent(); Collection<ECR> parentECRs = ImmutableList.copyOf(parent.getECRs()); for (ECR ecr : parentECRs) { ValueType ecrType = getType(ecr); if (ecrType.isStruct()) collapseStruct(ecr, ecrType.asStruct()); } enableOp(root); }
/** * Collapse <code>structECR</code> by merge it with all its element ECRs, and set its type as the * cell type (simple type might with top size) * * @param structECR * @param structT * @param ECRCache avoid structure cycle * @return */ private ValueType collapseStruct(ECR structECR, StructType structT, Collection<ECR> ECRCache) { // Ensure collapsed type to be simple ValueType unionType = null; // join components Collection<ECR> elems = structT.getFieldMap().asMapOfRanges().values(); Collection<ECR> cjoins = Sets.newHashSet(); Collection<Pair<Size, ECR>> ccjoins = Sets.newHashSet(); for (ECR elem : elems) { ECR elemLoc = getLoc(elem); ValueType elemLocType = getType(elemLoc); Parent parent = elemLocType.getParent().removeECR(structECR); elemLocType.setParent(parent); if (!ECRCache.add(elemLoc)) continue; // ECRCache has elemLoc cjoins.addAll(getCjoins(elemLoc)); elemLoc.clearCCjoins(ccjoins); ccjoins.addAll(getCCjoins(elemLoc)); elemLoc.clearCCjoins(ccjoins); if (elemLocType.isStruct()) { elemLocType = collapseStruct(elemLoc, elemLocType.asStruct(), ECRCache); } union(structECR, elemLoc); unionType = unionType == null ? elemLocType : unify(unionType, elemLocType); } unionType = unionType == null ? ValueType.bottom() : unionType; setType(structECR, unionType); ECR root = findRoot(structECR); for (Pair<Size, ECR> cjoinPair : ccjoins) ccjoin(cjoinPair.fst(), root, cjoinPair.snd()); for (ECR joinECR : cjoins) cjoin(root, joinECR); return unionType; }
/** * Unify value types <code>t1</code> and <code>t2</code> * * @param t1 * @param t2 * @return a unified value type */ ValueType unify(ValueType t1, ValueType t2) { Pair<ValueType, ValueType> pair = swap(t1, t2); t1 = pair.fst(); t2 = pair.snd(); if (t1.equals(t2)) return t1; if (t1.isBottom()) { if (t1.hasOpTag()) t2.enableOpTag(); return t2; } Parent parent = Parent.getLUB(t1.getParent(), t2.getParent()); Size size = Size.getLUB(t1.getSize(), t2.getSize()); boolean hasOpTag = t1.hasOpTag() || t2.hasOpTag(); switch (t1.getKind()) { case BLANK: { switch (t2.getKind()) { case BLANK: return ValueType.blank(size, parent, hasOpTag); case SIMPLE: { return ValueType.simple( t2.asSimple().getLoc(), t2.asSimple().getFunc(), size, parent, hasOpTag); } default: { // case STRUCT: return ValueType.struct(t2.asStruct().getFieldMap(), size, parent, hasOpTag); } } } case SIMPLE: { switch (t2.getKind()) { case SIMPLE: { ECR loc1 = t1.asSimple().getLoc(); ECR loc2 = t2.asSimple().getLoc(); ECR func1 = t1.asSimple().getFunc(); ECR func2 = t2.asSimple().getFunc(); ECR loc = join(loc1, loc2); ECR func = join(func1, func2); return ValueType.simple(loc, func, size, parent, hasOpTag); } default: // case STRUCT: throw new IllegalArgumentException(); } } case STRUCT: { if (ValueTypeKind.STRUCT.equals(t2.getKind())) { RangeMap<Long, ECR> map = getCompatibleMap(t1.asStruct(), t2.asStruct()); return ValueType.struct(map, size, parent, hasOpTag); } else { throw new IllegalArgumentException(); } } default: { // Lambda assert (t2.isLambda()); List<ECR> params = Lists.newArrayList(); Iterator<ECR> paramItr1 = t1.asLambda().getParams().iterator(); Iterator<ECR> paramItr2 = t2.asLambda().getParams().iterator(); while (paramItr1.hasNext() && paramItr2.hasNext()) { ECR param1 = paramItr1.next(); ECR param2 = paramItr2.next(); ECR param = join(param1, param2); params.add(param); } while (paramItr1.hasNext()) params.add(paramItr1.next()); while (paramItr2.hasNext()) params.add(paramItr2.next()); ECR ret1 = t1.asLambda().getRet(); ECR ret2 = t2.asLambda().getRet(); ECR ret = join(ret1, ret2); return ValueType.lam(ret, params, parent); } } }
void ccjoin(Size rangeSize, ECR e1, ECR e2) { ValueType type1 = getType(e1); if (type1.isBottom()) { addCCjoin(rangeSize, e1, e2); return; } Size size1 = type1.getSize(); if (!Size.isLessThan(rangeSize, size1)) { addCCjoin(rangeSize, e1, e2); expand(e1, rangeSize); // expand(e1) would call setType(e1, ...) and thus ccjoin(e1, e2) return; } if (e1.equals(e2)) return; switch (type1.getKind()) { case BLANK: { addCCjoin(rangeSize, e1, e2); ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: setType(e2, ValueType.blank(rangeSize, Parent.getBottom())); return; default: Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } } case SIMPLE: { ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: setType( e2, ValueType.simple( type1.asSimple().getLoc(), type1.asSimple().getFunc(), rangeSize, Parent.getBottom(), type2.hasOpTag())); return; case BLANK: { setType( e2, ValueType.simple( type1.asSimple().getLoc(), type1.asSimple().getFunc(), type2.getSize(), type2.getParent(), type2.hasOpTag())); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case SIMPLE: { cjoin(type1.asSimple().getLoc(), type2.asSimple().getLoc()); cjoin(type1.asSimple().getFunc(), type2.asSimple().getFunc()); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case STRUCT: { addCCjoin(rangeSize, e1, e2); collapseStruct(e2, type2.asStruct()); return; } default: // lambda return; } } case STRUCT: { ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: { RangeMap<Long, ECR> fieldMapCopy = FieldRangeMap.create(); fieldMapCopy.putAll(type1.asStruct().getFieldMap()); setType( e2, ValueType.struct( fieldMapCopy, rangeSize, Parent.getBottom(), type2.hasOpTag())); return; } case BLANK: { RangeMap<Long, ECR> fieldMapCopy = FieldRangeMap.create(); fieldMapCopy.putAll(type1.asStruct().getFieldMap()); Size size2 = type2.getSize(); setType( e2, ValueType.struct(fieldMapCopy, size2, type2.getParent(), type2.hasOpTag())); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case SIMPLE: { addCCjoin(rangeSize, e1, e2); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); for (ECR elemECR : type1.asStruct().getFieldMap().asMapOfRanges().values()) { ValueType elemType = getType(elemECR); Size elemSize = elemType.getSize(); ccjoin(elemSize, elemECR, e2); } return; } case STRUCT: { throw new IllegalArgumentException(); // Size size2 = type2.getSize(); // if(!Size.isLessThan(rangeSize, size2)) { // addCCjoin(rangeSize, e1, e2); // expand(e2, rangeSize); return; // } // // ValueType unifyStructType = unify(type1, type2); // unify structure type // eagerly // setType(e1, unifyStructType); // setType(e2, unifyStructType); // return; } default: return; // lambda } } default: return; // lambda } }