/** * 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; }
ECR cjoin(ECR e1, ECR e2) { if (e1.equals(e2)) return findRoot(e1); if (getType(e1).isBottom()) { Collection<ECR> joins2 = getCjoins(e2); Collection<Pair<Size, ECR>> cjoins2 = getCCjoins(e2); addCjoin(e1, e2); addCjoins(e1, joins2); addCCjoins(e1, cjoins2); return findRoot(e1); } return join(e1, e2); }
/** * Set type <code>e</code> as <code>type</code> * * @param e * @param type */ void setType(ECR e, ValueType type) { ECR root = findRoot(e); root.setType(type); Collection<Pair<Size, ECR>> ccjoins = ImmutableList.copyOf(root.getCCjoins()); root.clearCCjoins(ccjoins); for (Pair<Size, ECR> cjoinPair : ccjoins) ccjoin(cjoinPair.fst(), root, cjoinPair.snd()); Collection<ECR> cjoins = ImmutableList.copyOf(root.getCjoins()); root.clearCjoins(cjoins); for (ECR joinECR : cjoins) cjoin(root, joinECR); }
ECR join(ECR e1, ECR e2) { if (e1.equals(e2)) return e1; checkStructCollapse(e1, e2); ValueType t1 = getType(e1); ValueType t2 = getType(e2); Collection<Pair<Size, ECR>> ccjoins1 = ImmutableList.copyOf(getCCjoins(e1)); Collection<Pair<Size, ECR>> ccjoins2 = ImmutableList.copyOf(getCCjoins(e2)); Collection<ECR> cjoins1 = ImmutableList.copyOf(getCjoins(e1)); Collection<ECR> cjoins2 = ImmutableList.copyOf(getCjoins(e2)); ECR root = union(e1, e2); switch (t1.getKind()) { case BOTTOM: { switch (t2.getKind()) { case BOTTOM: { Collection<ECR> cjoins = Sets.newHashSet(); cjoins.addAll(cjoins1); cjoins.addAll(cjoins2); root.addCjoins(cjoins); Collection<Pair<Size, ECR>> ccjoins = Sets.newHashSet(); ccjoins.addAll(ccjoins1); ccjoins.addAll(ccjoins2); root.addCCjoins(ccjoins); break; } default: { root.setType(t2); root.clearCCjoins(ccjoins1); for (Pair<Size, ECR> pair : ccjoins1) ccjoin(pair.fst(), root, pair.snd()); root.clearCjoins(cjoins1); for (ECR cjoin : cjoins1) cjoin(root, cjoin); break; } } break; } default: { switch (t2.getKind()) { case BOTTOM: { root.setType(t1); root.clearCCjoins(ccjoins2); for (Pair<Size, ECR> pair : ccjoins2) ccjoin(pair.fst(), root, pair.snd()); root.clearCjoins(cjoins2); for (ECR cjoin : cjoins2) cjoin(root, cjoin); break; } default: { root.setType(t1); ValueType unionType = unify(t1, t2); ValueType freshType = getType(root); if (!freshType.equals(t1)) { unionType = resolveType(root, unionType, freshType); } root.setType(unionType); root.clearCCjoins(ccjoins1); root.clearCCjoins(ccjoins2); for (Pair<Size, ECR> pair : ccjoins1) ccjoin(pair.fst(), root, pair.snd()); for (Pair<Size, ECR> pair : ccjoins2) ccjoin(pair.fst(), root, pair.snd()); break; } } break; } } return root; }
/** * Create a pair of location ECR and function ECR, both with bottome type * * @return */ private Pair<ECR, ECR> createBottomLocFunc() { ECR loc = ECR.createBottom(); ECR func = ECR.createBottom(); return Pair.of(loc, func); }
/** * Get the root of ECR <code>e</code> * * @param e * @return */ ECR findRoot(ECR e) { return (ECR) e.findRoot(); }
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 } }