/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.frontend.typechecker.locationtypes.infer; import java.util.*; import abs.frontend.analyser.HasCogs; import abs.frontend.analyser.SemanticConditionList; import abs.frontend.ast.ASTNode; import abs.frontend.ast.AsyncCall; import abs.frontend.ast.Block; import abs.frontend.ast.Call; import abs.frontend.ast.ClassDecl; import abs.frontend.ast.Decl; import abs.frontend.ast.MainBlock; import abs.frontend.ast.Model; import abs.frontend.ast.NewExp; import abs.frontend.ast.SyncCall; import abs.frontend.ast.ThisExp; import abs.frontend.typechecker.Type; import abs.frontend.typechecker.ext.DefaultTypeSystemExtension; import abs.frontend.typechecker.ext.AdaptDirection; import abs.frontend.typechecker.ext.TypeSystemExtension; import abs.frontend.typechecker.locationtypes.LocationType; import abs.frontend.typechecker.locationtypes.LocationTypeExtension; public class LocationTypeInferrerExtension extends DefaultTypeSystemExtension { public static enum LocationTypingPrecision { BASIC, METHOD_LOCAL_FAR, CLASS_LOCAL_FAR, COMPILATION_UNIT_LOCAL_FAR, MODULE_LOCAL_FAR, GLOBAL_FAR } private static final int THRESHOLD = 5; private LocationTypingPrecision precision = LocationTypingPrecision.CLASS_LOCAL_FAR; public void setLocationTypingPrecision(LocationTypingPrecision p) { precision = p; } private Map<LocationTypeVariable, LocationType> results; private LocationType defaultType = LocationType.INFER; private Map<HasCogs, List<LocationType>> farTypes = new HashMap<HasCogs, List<LocationType>>(); public LocationTypeInferrerExtension(Model m) { super(m); } public void setDefaultType(LocationType type) { defaultType = type; } private Set<Constraint> constraints = new HashSet<Constraint>(); //private List<LocationType> globalFarTypes = new ArrayList<LocationType>(); boolean enablesStats;; public Set<Constraint> getConstraints() { return constraints; } public Map<LocationTypeVariable, LocationType> getResults() { return results; } public static LocationTypeVariable getLV(Type t) { LocationTypeVariable ltv = (LocationTypeVariable) t.getMetaData(LocationTypeVariable.VAR_KEY); return ltv; } private LocationTypeVariable adaptTo(LocationTypeVariable expLocType, AdaptDirection dir, LocationTypeVariable adaptTo, ASTNode<?> typeNode, ASTNode<?> originatingNode) { LocationTypeVariable tv = LocationTypeVariable.newVar(constraints, typeNode, false, getFarTypes(originatingNode), null); constraints.add(Constraint.adaptConstraint(tv, expLocType, dir, adaptTo)); //System.out.println("Require " + tv + " = " + expLocType + " |>" + adaptTo); return tv; } private void adaptAndSet(Type rht, AdaptDirection dir, LocationTypeVariable adaptTo, ASTNode<?> originatingNode) { if (adaptTo != LocationTypeVariable.ALWAYS_NEAR) { // Optimization LocationTypeVariable rhtlv = getLV(rht); LocationTypeVariable tv = adaptTo(rhtlv, dir, adaptTo, null, originatingNode); annotateVar(rht, tv); } } private void annotateVar(Type t, LocationTypeVariable tv) { t.addMetaData(LocationTypeVariable.VAR_KEY,tv); } private LocationTypeVariable addNewVar(Type t, ASTNode<?> originatingNode, ASTNode<?> typeNode) { LocationTypeExtension.getLocationTypeFromAnnotations(t, originatingNode); // check consistency of annotations LocationTypeVariable ltv = getLV(t); if (ltv != null) return ltv; LocationType lt = getLocationTypeOrDefault(t, originatingNode); LocationTypeVariable tv; if (lt.isInfer()) { tv = LocationTypeVariable.newVar(constraints, typeNode, true, getFarTypes(originatingNode), LocationTypeExtension.getLocationTypeFromAnnotations(t, originatingNode)); } else if (lt.isFar() && precision != LocationTypingPrecision.BASIC){ tv = LocationTypeVariable.newVar(constraints, typeNode, true, getFarTypes(originatingNode), LocationTypeExtension.getLocationTypeFromAnnotations(t, originatingNode)); @SuppressWarnings("unchecked") MultiListIterable<LocationType> fars = new MultiListIterable<LocationType>(Arrays.asList(LocationType.FAR), getFarTypes(originatingNode)); constraints.add(Constraint.constConstraint(tv, fars , Constraint.MUST_HAVE)); } else { tv = LocationTypeVariable.getFromLocationType(lt); } annotateVar(t, tv); return tv; } private List<LocationType> getFarTypes(ASTNode<?> originatingNode) { HasCogs node = null; String prefix = ""; if (precision == LocationTypingPrecision.GLOBAL_FAR) { node = originatingNode.getCompilationUnit().getModel(); prefix = "G"; } if (precision == LocationTypingPrecision.COMPILATION_UNIT_LOCAL_FAR) { node = originatingNode.getCompilationUnit(); prefix = "U"; } if (precision == LocationTypingPrecision.MODULE_LOCAL_FAR) { node = originatingNode.getModuleDecl(); prefix = "M"; } if (precision == LocationTypingPrecision.CLASS_LOCAL_FAR) { Decl d = originatingNode.getContextDecl(); if (d instanceof ClassDecl) { node = d; prefix = "C"; } Block b = originatingNode.getContextBlock(); if (b instanceof MainBlock) { node = b; prefix = "C"; } } if (precision == LocationTypingPrecision.METHOD_LOCAL_FAR) { Block b = originatingNode.getContextBlock(); if (b != null) { node = b; prefix = "M"; } } if (node == null) { return Collections.emptyList(); } final List<LocationType> e = farTypes.get(node); if (e != null) { return e; } else { List<LocationType> result = new ArrayList<LocationType>(); int numberOfNewCogs = node.getNumberOfNewCogExpr(); if (numberOfNewCogs > THRESHOLD) { numberOfNewCogs = THRESHOLD; } for (int i = 0; i < numberOfNewCogs; i++) { result.add(LocationType.createParametricFar(prefix + i)); } farTypes.put(node, result); return result; } } private LocationType getLocationTypeOrDefault(Type t, ASTNode<?> originatingNode) { LocationType lt = LocationTypeExtension.getLocationTypeFromAnnotations(t, originatingNode); if (lt == null) { return defaultType; } return lt; } @Override public void checkAssignable(Type adaptTo, AdaptDirection dir, Type rht, Type lht, ASTNode<?> n) { LocationTypeVariable sub = getLV(rht); LocationTypeVariable tv = getLV(lht); if (n instanceof NewExp && !((NewExp)n).hasLocal()) { constraints.add(Constraint.farConstraint(sub, tv)); } else { if (adaptTo != null && getLV(adaptTo) != LocationTypeVariable.ALWAYS_NEAR) { // Optimization sub = adaptTo(getLV(rht), dir, getLV(adaptTo), null, n); } constraints.add(Constraint.subConstraint(sub, tv)); } } @Override public void annotateType(Type t, ASTNode<?> originatingNode, ASTNode<?> typeNode) { if (originatingNode instanceof SyncCall) { } else if (originatingNode instanceof AsyncCall) { AsyncCall call = (AsyncCall)originatingNode; adaptAndSet(t, AdaptDirection.FROM, getLV(call.getCallee().getType()), originatingNode); } else if (originatingNode instanceof ThisExp) { annotateVar(t, LocationTypeVariable.ALWAYS_NEAR); } else if (originatingNode instanceof NewExp) { NewExp newExp = (NewExp)originatingNode; LocationTypeVariable ltv; if (!newExp.hasLocal()) { //ltv = LocationTypeVariable.ALWAYS_FAR; ltv = LocationTypeVariable.newVar(constraints, typeNode, false, getFarTypes(originatingNode), null); @SuppressWarnings("unchecked") MultiListIterable<LocationType> mi = new MultiListIterable<LocationType>(Arrays.asList(LocationType.FAR), getFarTypes(originatingNode)); constraints.add(Constraint.constConstraint(ltv, mi, Constraint.MUST_HAVE)); } else { ltv = LocationTypeVariable.ALWAYS_NEAR; } annotateVar(t, ltv); } else { if (t.isReferenceType()) { addNewVar(t, originatingNode, typeNode); } if (t.isNullType()) { annotateVar(t, LocationTypeVariable.ALWAYS_BOTTOM); } } } @Override public void checkMethodCall(Call call) { LocationTypeVariable lv = getLV(call.getCallee().getType()); assert lv != null : "Can't get LV for " + call.getCallee().getType().toString(); if (call instanceof SyncCall) { //checkEq(lv, LocationTypeVariable.ALWAYS_NEAR, Constraint.SHOULD_HAVE); constraints.add(Constraint.constConstraint(lv, LocationType.NEAR, Constraint.SHOULD_HAVE)); } else { //checkNeq(getLV(call.getCallee().getType()), LocationTypeVariable.ALWAYS_BOTTOM, Constraint.SHOULD_HAVE); //@SuppressWarnings("unchecked") //Iterable<LocationType> lts = new MultiListIterable<LocationType>(Arrays.asList(LocationType.ALLCONCRETEUSERTYPES), ); constraints.add(Constraint.constConstraint(lv, lv.allCTypes, Constraint.SHOULD_HAVE)); } } private void checkEq(LocationTypeVariable ltv1, LocationTypeVariable ltv2, Integer importance) { constraints.add(Constraint.eqConstraint(ltv1, ltv2, importance)); } @Override public void checkEq(Type t1, Type t2, ASTNode<?> node) { checkEq(getLV(t1), getLV(t2), Constraint.SHOULD_HAVE); } @Override public void finished() { if (enablesStats) { for (int i = 0; i < 4; i++) { SatGenerator satGen = new SatGenerator(constraints); //satGen.enableStats = enablesStats; results = satGen.generate(errors); } } SatGenerator satGen = new SatGenerator(constraints); satGen.enableStats = enablesStats; results = satGen.generate(errors); if (!errors.containsErrors()) { SemanticConditionList sel = new SemanticConditionList(); List<TypeSystemExtension> curr = model.getTypeExt().getTypeSystemExtensionList(); model.getTypeExt().clearTypeSystemExtensions(); model.getTypeExt().register(new LocationTypeExtension(model, this)); model.typeCheck(sel); errors.addAll(sel); model.getTypeExt().clearTypeSystemExtensions(); model.getTypeExt().registerAll(curr); } } public void enableStatistics() { enablesStats = true; } public LocationType getDefaultType() { return defaultType; } }