From 2476e4b18ed88f17e423734749518a32e11ce679 Mon Sep 17 00:00:00 2001 From: bdemsky Date: Mon, 15 Jun 2009 23:09:28 +0000 Subject: [PATCH] changes: (1) Add support for synchronized blocks (2) Fix analysis bug (3) Start support for delaying operations until commit --- .../Analysis/Locality/DelayComputation.java | 228 ++++++++++++++++++ .../Analysis/Locality/DiscoverConflicts.java | 12 +- Robust/src/Analysis/Loops/CSE.java | 6 +- .../src/Analysis/Loops/GlobalFieldType.java | 88 +++++++ Robust/src/Analysis/Loops/LoopInvariant.java | 6 +- Robust/src/Analysis/Loops/localCSE.java | 6 +- Robust/src/IR/Flat/BuildFlat.java | 20 ++ Robust/src/IR/Tree/BuildIR.java | 4 + Robust/src/IR/Tree/Kind.java | 1 + Robust/src/IR/Tree/SemanticCheck.java | 11 + Robust/src/IR/TypeDescriptor.java | 2 +- Robust/src/Parse/java14.cup | 16 +- 12 files changed, 383 insertions(+), 17 deletions(-) create mode 100644 Robust/src/Analysis/Locality/DelayComputation.java diff --git a/Robust/src/Analysis/Locality/DelayComputation.java b/Robust/src/Analysis/Locality/DelayComputation.java new file mode 100644 index 00000000..5a8fe1ae --- /dev/null +++ b/Robust/src/Analysis/Locality/DelayComputation.java @@ -0,0 +1,228 @@ +package Analysis.Locality; +import IR.State; +import IR.MethodDescriptor; +import IR.TypeDescriptor; +import IR.FieldDescriptor; +import IR.Flat.*; +import Analysis.Loops.GlobalFieldType; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; +import java.util.Iterator; + +public class DelayComputation { + State state; + LocalityAnalysis locality; + TypeAnalysis typeanalysis; + GlobalFieldType gft; + + public DelayComputation(LocalityAnalysis locality, State state, TypeAnalysis typeanalysis, GlobalFieldType gft) { + this.locality=locality; + this.state=state; + this.typeanalysis=typeanalysis; + this.gft=gft; + } + + public void doAnalysis() { + Set localityset=locality.getLocalityBindings(); + for(Iterator lb=localityset.iterator();lb.hasNext();) { + analyzeMethod(lb.next()); + } + } + + public void analyzeMethod(LocalityBinding lb) { + MethodDescriptor md=lb.getMethod(); + FlatMethod fm=state.getMethodFlat(md); + HashSet cannotdelay=new HashSet(); + Hashtable atomictable=locality.getAtomic(lb); + if (lb.isAtomic()) { + //We are in a transaction already... + //skip past this method or something + return; + } + + HashSet toanalyze=new HashSet(); + toanalyze.addAll(fm.getNodeSet()); + + //Build the hashtables + Hashtable> nodelaytemps=new Hashtable>(); + Hashtable> nodelayfieldswr=new Hashtable>(); + Hashtable> nodelayarrayswr=new Hashtable>(); + Hashtable> nodelayfieldsrd=new Hashtable>(); + Hashtable> nodelayarraysrd=new Hashtable>(); + + //Effect of adding something to nodelay set is to move it up past everything in delay set + //Have to make sure we can do this commute + + while(!toanalyze.isEmpty()) { + FlatNode fn=toanalyze.iterator().next(); + toanalyze.remove(fn); + + boolean isatomic=atomictable.get(fn).intValue()>0; + + if (!isatomic) + continue; + boolean isnodelay=false; + + /* Compute incoming nodelay sets */ + HashSet nodelaytempset=new HashSet(); + HashSet nodelayfieldwrset=new HashSet(); + HashSet nodelayarraywrset=new HashSet(); + HashSet nodelayfieldrdset=new HashSet(); + HashSet nodelayarrayrdset=new HashSet(); + for(int i=0;i localityset=locality.getLocalityBindings(); for(Iterator lb=localityset.iterator();lb.hasNext();) { computeModified(lb.next()); @@ -383,7 +385,8 @@ public class DiscoverConflicts { return tmptofnset; } - /* See what fields and arrays transactions might modify. */ + /* See what fields and arrays transactions might modify. We only + * look at changes to old objects. */ public void computeModified(LocalityBinding lb) { MethodDescriptor md=lb.getMethod(); @@ -408,6 +411,11 @@ public class DiscoverConflicts { } } + + //Returns a table that maps a flatnode to a set of temporaries + //This set of temporaries is old (meaning they may point to object + //allocated before the beginning of the current transaction + Hashtable> computeOldTemps(LocalityBinding lb) { Hashtable> fntooldtmp=new Hashtable>(); HashSet discovered=new HashSet(); diff --git a/Robust/src/Analysis/Loops/CSE.java b/Robust/src/Analysis/Loops/CSE.java index c1776848..e3ce5828 100644 --- a/Robust/src/Analysis/Loops/CSE.java +++ b/Robust/src/Analysis/Loops/CSE.java @@ -55,9 +55,9 @@ public class CSE { { FlatCall fc=(FlatCall) fn; MethodDescriptor md=fc.getMethod(); - Set fields=gft.getFields(md); - Set arrays=gft.getArrays(md); - killexpressions(tab, fields, arrays, gft.containsAtomic(md)||gft.containsBarrier(md)); + Set fields=gft.getFieldsAll(md); + Set arrays=gft.getArraysAll(md); + killexpressions(tab, fields, arrays, gft.containsAtomicAll(md)||gft.containsBarrierAll(md)); break; } case FKind.FlatOpNode: diff --git a/Robust/src/Analysis/Loops/GlobalFieldType.java b/Robust/src/Analysis/Loops/GlobalFieldType.java index c81fdab5..3aa5ef89 100644 --- a/Robust/src/Analysis/Loops/GlobalFieldType.java +++ b/Robust/src/Analysis/Loops/GlobalFieldType.java @@ -18,6 +18,8 @@ public class GlobalFieldType { MethodDescriptor root; Hashtable> fields; Hashtable> arrays; + Hashtable> fieldsrd; + Hashtable> arraysrd; HashSet containsAtomic; HashSet containsBarrier; @@ -27,6 +29,8 @@ public class GlobalFieldType { this.root=root; this.fields=new Hashtable>(); this.arrays=new Hashtable>(); + this.fieldsrd=new Hashtable>(); + this.arraysrd=new Hashtable>(); this.containsAtomic=new HashSet(); this.containsBarrier=new HashSet(); doAnalysis(); @@ -84,6 +88,10 @@ public class GlobalFieldType { changed=true; if (arrays.get(md).addAll(arrays.get(md2))) changed=true; + if (fieldsrd.get(md).addAll(fieldsrd.get(md2))) + changed=true; + if (arraysrd.get(md).addAll(arraysrd.get(md2))) + changed=true; if (containsAtomic.contains(md2)) { if (containsAtomic.add(md)) changed=true; @@ -113,9 +121,83 @@ public class GlobalFieldType { return arrays.get(md); } + public Set getFieldsRd(MethodDescriptor md) { + return fieldsrd.get(md); + } + + public Set getArraysRd(MethodDescriptor md) { + return arraysrd.get(md); + } + + public boolean containsAtomicAll(MethodDescriptor md) { + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (containsAtomic.contains(md2)) + return true; + } + return false; + } + + public boolean containsBarrierAll(MethodDescriptor md) { + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (containsBarrier.contains(md2)) + return true; + } + return false; + } + + public Set getFieldsAll(MethodDescriptor md) { + HashSet s=new HashSet(); + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (fields.containsKey(md2)) + s.addAll(fields.get(md2)); + } + return s; + } + + public Set getArraysAll(MethodDescriptor md) { + HashSet s=new HashSet(); + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (arrays.containsKey(md2)) + s.addAll(arrays.get(md2)); + } + return s; + } + + public Set getFieldsRdAll(MethodDescriptor md) { + HashSet s=new HashSet(); + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (fieldsrd.containsKey(md2)) + s.addAll(fieldsrd.get(md2)); + } + return s; + } + + public Set getArraysRdAll(MethodDescriptor md) { + HashSet s=new HashSet(); + Set methodset=cg.getMethods(md); + for(Iterator it=methodset.iterator();it.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)it.next(); + if (arraysrd.containsKey(md2)) + s.addAll(arraysrd.get(md2)); + } + return s; + } + public void analyzeMethod(MethodDescriptor md) { fields.put(md, new HashSet()); arrays.put(md, new HashSet()); + fieldsrd.put(md, new HashSet()); + arraysrd.put(md, new HashSet()); FlatMethod fm=st.getMethodFlat(md); for(Iterator it=fm.getNodeSet().iterator();it.hasNext();) { @@ -123,9 +205,15 @@ public class GlobalFieldType { if (fn.kind()==FKind.FlatSetElementNode) { FlatSetElementNode fsen=(FlatSetElementNode)fn; arrays.get(md).add(fsen.getDst().getType()); + } else if (fn.kind()==FKind.FlatElementNode) { + FlatElementNode fen=(FlatElementNode)fn; + arraysrd.get(md).add(fen.getSrc().getType()); } else if (fn.kind()==FKind.FlatSetFieldNode) { FlatSetFieldNode fsfn=(FlatSetFieldNode)fn; fields.get(md).add(fsfn.getField()); + } else if (fn.kind()==FKind.FlatFieldNode) { + FlatFieldNode ffn=(FlatFieldNode)fn; + fieldsrd.get(md).add(ffn.getField()); } else if (fn.kind()==FKind.FlatAtomicEnterNode) { containsAtomic.add(md); } else if (fn.kind()==FKind.FlatCall) { diff --git a/Robust/src/Analysis/Loops/LoopInvariant.java b/Robust/src/Analysis/Loops/LoopInvariant.java index 9fbc9990..60bdc5a9 100644 --- a/Robust/src/Analysis/Loops/LoopInvariant.java +++ b/Robust/src/Analysis/Loops/LoopInvariant.java @@ -72,13 +72,13 @@ public class LoopInvariant { } else if (fn.kind()==FKind.FlatCall) { FlatCall fcall=(FlatCall)fn; MethodDescriptor md=fcall.getMethod(); - Set f=gft.getFields(md); - Set t=gft.getArrays(md); + Set f=gft.getFieldsAll(md); + Set t=gft.getArraysAll(md); if (f!=null) fields.addAll(f); if (t!=null) types.addAll(t); - if (gft.containsAtomic(md)||gft.containsBarrier(md)) { + if (gft.containsAtomicAll(md)||gft.containsBarrierAll(md)) { unsafe=true; } } else if (fn.kind()==FKind.FlatSetFieldNode) { diff --git a/Robust/src/Analysis/Loops/localCSE.java b/Robust/src/Analysis/Loops/localCSE.java index 108d992e..b42c9955 100644 --- a/Robust/src/Analysis/Loops/localCSE.java +++ b/Robust/src/Analysis/Loops/localCSE.java @@ -154,9 +154,9 @@ public class localCSE { //do side effects FlatCall fc=(FlatCall)fn; MethodDescriptor md=fc.getMethod(); - Set fields=gft.getFields(md); - Set arrays=gft.getArrays(md); - kill(table, fields, arrays, gft.containsAtomic(md), gft.containsBarrier(md)); + Set fields=gft.getFieldsAll(md); + Set arrays=gft.getArraysAll(md); + kill(table, fields, arrays, gft.containsAtomicAll(md), gft.containsBarrierAll(md)); } default: { TempDescriptor[] writes=fn.writesTemps(); diff --git a/Robust/src/IR/Flat/BuildFlat.java b/Robust/src/IR/Flat/BuildFlat.java index d2f4727a..3e683db3 100644 --- a/Robust/src/IR/Flat/BuildFlat.java +++ b/Robust/src/IR/Flat/BuildFlat.java @@ -1136,6 +1136,23 @@ public class BuildFlat { return flattenBlockNode(sbn.getBlockNode()); } + private NodePair flattenSynchronizedNode(SynchronizedNode sbn) { + TempDescriptor montmp=TempDescriptor.tempFactory("monitor",sbn.getExpr().getType()); + NodePair npexp=flattenExpressionNode(sbn.getExpr(), montmp); + NodePair npblock=flattenBlockNode(sbn.getBlockNode()); + + MethodDescriptor menmd=(MethodDescriptor)typeutil.getClass("Object").getMethodTable().get("MonitorEnter"); + FlatCall fcen=new FlatCall(menmd, null, montmp, new TempDescriptor[0]); + + MethodDescriptor mexmd=(MethodDescriptor)typeutil.getClass("Object").getMethodTable().get("MonitorExit"); + FlatCall fcex=new FlatCall(mexmd, null, montmp, new TempDescriptor[0]); + + npexp.getEnd().addNext(fcen); + fcen.addNext(npblock.getBegin()); + npblock.getEnd().addNext(fcex); + return new NodePair(npexp.getBegin(), fcex); + } + private NodePair flattenAtomicNode(AtomicNode sbn) { NodePair np=flattenBlockNode(sbn.getBlockNode()); FlatAtomicEnterNode faen=new FlatAtomicEnterNode(); @@ -1276,6 +1293,9 @@ public class BuildFlat { case Kind.AtomicNode: return flattenAtomicNode((AtomicNode)bsn); + case Kind.SynchronizedNode: + return flattenSynchronizedNode((SynchronizedNode)bsn); + case Kind.SESENode: return flattenSESENode((SESENode)bsn); diff --git a/Robust/src/IR/Tree/BuildIR.java b/Robust/src/IR/Tree/BuildIR.java index f57330cf..2e2fc524 100644 --- a/Robust/src/IR/Tree/BuildIR.java +++ b/Robust/src/IR/Tree/BuildIR.java @@ -701,6 +701,10 @@ public class BuildIR { } else if (isNode(pn,"atomic")) { BlockNode bn=parseBlockHelper(pn); blockstatements.add(new AtomicNode(bn)); + } else if (isNode(pn,"synchronized")) { + BlockNode bn=parseBlockHelper(pn.getChild("block")); + ExpressionNode en=parseExpression(pn.getChild("expr").getFirstChild()); + blockstatements.add(new SynchronizedNode(en, bn)); } else if (isNode(pn,"return")) { if (isEmpty(pn.getTerminal())) blockstatements.add(new ReturnNode()); diff --git a/Robust/src/IR/Tree/Kind.java b/Robust/src/IR/Tree/Kind.java index a50a67f6..40375f46 100644 --- a/Robust/src/IR/Tree/Kind.java +++ b/Robust/src/IR/Tree/Kind.java @@ -28,4 +28,5 @@ public class Kind { public final static int TertiaryNode=25; public final static int InstanceOfNode=26; public final static int ArrayInitializerNode=27; + public final static int SynchronizedNode=28; } diff --git a/Robust/src/IR/Tree/SemanticCheck.java b/Robust/src/IR/Tree/SemanticCheck.java index 0f731f91..389fc208 100644 --- a/Robust/src/IR/Tree/SemanticCheck.java +++ b/Robust/src/IR/Tree/SemanticCheck.java @@ -296,6 +296,10 @@ public class SemanticCheck { checkAtomicNode(md, nametable, (AtomicNode)bsn); return; + case Kind.SynchronizedNode: + checkSynchronizedNode(md, nametable, (SynchronizedNode)bsn); + return; + case Kind.ContinueBreakNode: checkContinueBreakNode(md, nametable, (ContinueBreakNode) bsn); return; @@ -343,6 +347,12 @@ public class SemanticCheck { checkBlockNode(md, nametable, sbn.getBlockNode()); } + void checkSynchronizedNode(Descriptor md, SymbolTable nametable, SynchronizedNode sbn) { + checkBlockNode(md, nametable, sbn.getBlockNode()); + //todo this could be Object + checkExpressionNode(md, nametable, sbn.getExpr(), null); + } + void checkContinueBreakNode(Descriptor md, SymbolTable nametable, ContinueBreakNode cbn) { if (loopstack.empty()) throw new Error("continue/break outside of loop"); @@ -485,6 +495,7 @@ public class SemanticCheck { fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname); if (fd==null) throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md); + if (fd.getType().iswrapper()) { FieldAccessNode fan2=new FieldAccessNode(left, fieldname); fan2.setField(fd); diff --git a/Robust/src/IR/TypeDescriptor.java b/Robust/src/IR/TypeDescriptor.java index 7725f610..4ee68570 100644 --- a/Robust/src/IR/TypeDescriptor.java +++ b/Robust/src/IR/TypeDescriptor.java @@ -58,7 +58,7 @@ public class TypeDescriptor extends Descriptor { } public boolean iswrapper() { - if (arraycount!=0||!isClass()) + if (arraycount!=0||isClass()) return false; return (name.equals("bytewrapper")|| name.equals("booleanwrapper")|| diff --git a/Robust/src/Parse/java14.cup b/Robust/src/Parse/java14.cup index edc61cb7..01f07d0d 100644 --- a/Robust/src/Parse/java14.cup +++ b/Robust/src/Parse/java14.cup @@ -188,7 +188,8 @@ non terminal ParseNode statement_expression_list; non terminal ParseNode break_statement, continue_statement; non terminal ParseNode return_statement; //non terminal ParseNode throw_statement; -//non terminal ParseNode synchronized_statement, try_statement; +non terminal ParseNode synchronized_statement; +//non terminal ParseNode try_statement; //non terminal ParseNode catches_opt; //non terminal ParseNode catches, catch_clause; //non terminal ParseNode finally; @@ -1188,7 +1189,7 @@ statement_without_trailing_substatement ::= | task_exitstatement:st {: RESULT=st; :} | atomic_statement:st {: RESULT=st; :} | sese_statement:st {: RESULT=st; :} -// | synchronized_statement + | synchronized_statement:st {: RESULT=st; :} // | throw_statement // | try_statement // | assert_statement @@ -1362,9 +1363,14 @@ return_statement ::= //throw_statement ::= // THROW expression SEMICOLON // ; -//synchronized_statement ::= -// SYNCHRONIZED LPAREN expression RPAREN block -// ; +synchronized_statement ::= + SYNCHRONIZED LPAREN expression:e RPAREN block:b {: + ParseNode pn=new ParseNode("synchronized"); + pn.addChild("expr").addChild(e); + pn.addChild("block").addChild(b); + RESULT=pn; + :} + ; atomic_statement ::= ATOMIC block:blk {: RESULT=(new ParseNode("atomic")).addChild(blk).getRoot(); -- 2.34.1