cs 497 program analysis
play

CS 497 Program Analysis Ond rej Lhot ak November 21 and 26, 2007 - PowerPoint PPT Presentation

CS 497 Program Analysis Ond rej Lhot ak November 21 and 26, 2007 Program Analysis Prove properties about runtime behaviour of a program without running it Program Analysis Prove properties about runtime behaviour of a program without


  1. Designing a Dataflow Analysis Forwards or backwards? 1 What are the lattice elements? 2 Must the property hold on all paths, or must there exist a 3 path? (What is the join operator?) On a given path, what are we trying to compute? What 4 are the flow equations? What values hold for program entry points? 5 (What is the initial estimate?) 6 It’s the unique element ⊥ such that ∀ x . ⊥ ⊔ x = x .

  2. Interprocedural Analysis Motivation a = 1; a = 1; b = 2; b = 2; c = a + b; c = 3;

  3. Interprocedural Analysis Motivation a = 1; a = 1; b = 2; b = 2; foo(); foo() c = a + b; c = ???; Does foo() modify a or b?

  4. Interprocedural Analysis Motivation a = 1; a = 1; b = 2; b = 2; foo(); foo() c = a + b; c = ???; Does foo() modify a or b? int double(int x) { return 2*x; } a = 2; b = double(a); c = double(b); Are b and c constant?

  5. Control Flow Supergraph a = 2; b = double(a); c = double(b);

  6. Control Flow Supergraph a = 2; b = double(a); c = double(b);

  7. Context Sensitivity via Cloning a = 2; b = double(a); c = double(b);

  8. Call Graph Example A call graph comprises: edges from call sites to methods invoked set of reachable methods

  9. Call Graph Analysis Motivation (Almost) every interprocedural analysis requires CG CG precision affects precision and cost of other analyses Open Challenges Precision for OO and functional languages Analysis of large programs Conservative analysis of incomplete programs

  10. 0CFA: An Analysis for Call Graph Construction Forwards or backwards? 1 What are the lattice elements? 2 Must the property hold on all paths, or must there exist a 3 path? (What is the join operator?) On a given path, what are we trying to compute? What 4 are the flow equations? What values hold for program entry points? 5 (What is the initial estimate?) 6 It’s the unique element ⊥ such that ∀ x . ⊥ ⊔ x = x .

  11. Tracematch Example List list = new LinkedList(); Iterator it = list.iterator(); while(it.hasNext()) { System.out.println( it.next()); }

  12. Tracematch Example create iterator List list = new LinkedList(); next hasNext next Iterator it = list.iterator(); while(it.hasNext()) { update list hasNext System.out.println( update list it.next()); } next, hasNext

  13. Tracematch Analysis Motivation Document intended usage patterns of interfaces Automatically check for violations Challenges Objects referenced indirectly through pointers Tracking multiple interacting objects Enough precision to be useful

  14. File Closing Example tracematch( File f ) { sym open after returning(f): call(File open(..)); sym close after: call(void File.close(..)) && target(f); sym quit after: execution(void main(String[])); open quit { f.close(); } }

  15. Aspect-Oriented Programming Purpose modularize cross-cutting concerns How? An aspect: observes program execution for specified events executes specified code when events occur AspectJ aspect-oriented extension of Java

  16. Definitions joinpoint An identifiable run-time event (e.g. execution of a method) shadow Location in program source code of joinpoint start/end pointcut A predicate (expression) on joinpoints advice Code to be executed at a joinpoint aspect A collection of � pointcut, advice � pairs

  17. Tracematches An aspect comprises: advice pointcut A tracematch comprises: advice an alphabet of symbols, each associated with a pointcut a regular language over the symbol alphabet a set of parameters

  18. File Closing Example tracematch( File f ) { sym open after returning(f): call(File open(..)); sym close after: call(void File.close(..)) && target(f); sym quit after: execution(void main(String[])); open quit { f.close(); } }

  19. Declarative semantics: How TMs ought to work trace { File a, b, c, d; open(X) a = open("X"); d = a; open(Y) b = open("Y"); b.close(); close(Y) open(Z) c = open("Z"); d.close(); close(X) } quit Pattern: open quit

  20. Declarative semantics: How TMs ought to work trace X Y Z { File a, b, c, d; open(X) open a = open("X"); d = a; open(Y) open b = open("Y"); b.close(); close(Y) close open(Z) open c = open("Z"); d.close(); close(X) close } quit quit quit quit no no match Pattern: open quit

  21. Subject-Observer Example tracematch(Subject s, Observer o) { sym create after returning(o): call(Observer.new(..)) && args(s); sym update after: call(* Subject.update(..)) && target(s); create update* { o.update_view(); } }

  22. Operational Semantics 0 Notation � Q , A , q 0 , Q f , δ � is the tracematch finite automaton. tr � a � is a transition statement with symbol a ∈ A ˚ σ is a function from states ( Q ) to boolean formulas . The intended meaning is that the automaton is in state q if and only if the formula ˚ σ ( q ) evaluates to true . ˚ e = true   �  ∨ (˚ � tr � a � , ˚ σ � ˚ → λ i . ˚ σ ( j ) ∧ ˚ e σ ( i ) ∧ ¬ ˚ e )  j : δ ( j , a , i )

  23. Operational Semantics 1 Notation � Q , A , q 0 , Q f , δ � is the tracematch finite automaton. tr � a , b � is a transition statement with symbol a ∈ A and variable mapping b . ˚ σ is a function from states ( Q ) to boolean formulas over parameter values. The intended meaning is that the automaton associated with a given set of parameter values is in state q if and only if the formula ˚ σ ( q ) evaluates to true for those parameter values. � ˚ e ( b , ρ ) = ( f = ρ ( b ( f ))) f ∈ dom ( b )   �  ∨ (˚ � tr � a , b � , ˚ σ � ˚ → λ i . ˚ σ ( j ) ∧ ˚ e ( b , ρ ) σ ( i ) ∧ ¬ ˚ e ( b , ρ ))  j : δ ( j , a , i )

  24. Operational Semantics 2 σ ⊆ Q × ( F → D ) where Q is set of tracematch states, F is set of tracematch parameters, D is ⊤ o 3 o 2 o 1 positive bindings ¬ o 1 ¬ o 2 ¬ o 3 ¬ o 1 ¬ o 2 ¬ o 1 ¬ o 3 ¬ o 2 ¬ o 3 negative bindings ¬ o 1 ¬ o 2 ¬ o 3 ⊥

  25. Operational Semantics 2 � ρ ( b ( f )) if f ∈ dom ( b ) pos ( b , ρ )( f ) = ⊥ otherwise � if f = f ′ { ρ ( b ( f )) } neg ( b , ρ, f )( f ′ ) = ⊥ otherwise � tr � a , b � , σ � → {� i , m ⊔ pos ( b , ρ ) � : � j , m � ∈ σ ∧ δ ( j , a , i ) } ∪ {� i , m ⊔ neg ( b , ρ, f ) � : � i , m � ∈ σ ∧ f ∈ dom ( b ) }

  26. Theorems Declarative semantics ⇐ ⇒ Operational semantics 1 ⇐ ⇒ Operational semantics 2

  27. Iterator Example tracematch( List l, Iterator i ) { sym create after returning(i): call(Iterator List.iterator()) && target(l); sym update before: call(* List.add(..)) && target(l); sym next before: call(* Iterator.next()) && target(i); create next* update next { throw new ConcurrentModificationException(); } }

  28. Analysis 1: Missing Shadows Example Code { List l = new ArrayList(); Iterator i = l.iterator(); // create l.add(null); // update } Pattern: create next* update next No next = ⇒ no match

  29. Analysis 2: Flow-insensitive Consistent Shadows Example Code { List l1 = new ArrayList(); List l2 = new ArrayList(); Iterator i1 = l1.iterator(); // create l2.add(null); // update i1.next(); // next } Pattern: create next* update next No update on l1 ; no next on l2 = ⇒ no match

  30. Analysis 3: Flow-sensitive Active Shadows Example Code { List l = new ArrayList(); Iterator i = l.iterator(); // create i.next(); // next l.add(null); // update } Pattern: create next* update next No next after update = ⇒ no match

  31. What do we need to know? List list; Iterator iter; while(condition) { list = new ArrayList(); list.add(null); // update iter = list.iterator(); // create iter.next(); // next } Pattern: create next* update next Question: Do the two red list s always point to the same object?

  32. A bigger example void flat(List<List<Integer>> in, List<Integer> out) { for(Iterator it = in.iterator(); it.hasNext();) { List<Integer> l = it.next(); for(Iterator it2 = l.iterator(); it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  33. What we need to know Which variables point to the same/different objects. 1 For each object, which variables point to it at different 2 times.

  34. Analysis abstraction Each concrete object is represented by the set of variables that point to it. β o ( o ) = { v ∈ V : ρ ( v ) = o } A concrete environment is represented as the set of all abstract objects: β ρ ( ρ ) = { β o ( o ) : o is live } Dataflow analysis lattice is �P ( P ( V )) , ⊆� . If a set o ♯ is not empty, then it represents at most one concrete object: the object pointed to by the variables in o ♯ .

  35. Analysis transfer function � o ♯ ∪ { v 1 } if v 2 ∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) = o ♯ \ { v 1 } if v 2 �∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v 1 ← v 2 � ρ ♯ ( ρ ♯ ) � = o ♯ \ { v } � v ← new � o ♯ ( o ♯ ) = � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v ← new � ρ ♯ ( ρ ♯ ) � = ∪ {{ v }}

  36. Analysis transfer function � o ♯ ∪ { v 1 } if v 2 ∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) = o ♯ \ { v 1 } if v 2 �∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v 1 ← v 2 � ρ ♯ ( ρ ♯ ) � = o ♯ \ { v } � v ← new � o ♯ ( o ♯ ) = � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v ← new � ρ ♯ ( ρ ♯ ) � = ∪ {{ v }} � v ← heap field � ρ ♯ ( ρ ♯ ) = ???

  37. Analysis transfer function � o ♯ ∪ { v 1 } if v 2 ∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) = o ♯ \ { v 1 } if v 2 �∈ o ♯ � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v 1 ← v 2 � ρ ♯ ( ρ ♯ ) � = o ♯ \ { v } � v ← new � o ♯ ( o ♯ ) = � v 1 ← v 2 � o ♯ ( o ♯ ) : o ♯ ∈ ρ ♯ � � v ← new � ρ ♯ ( ρ ♯ ) � = ∪ {{ v }} ρ ♯ ∪ { o ♯ ∪ { v } : o ♯ ∈ ρ ♯ } � v ← heap field � ρ ♯ ( ρ ♯ ) =

  38. What the abstraction tells us Must aliasing If v 1 and v 2 always point to the same object, then every o ♯ ∈ ρ ♯ contains either both v 1 and v 2 , or neither. May aliasing If v 1 and v 2 cannot point to the same object, then no o ♯ ∈ ρ ♯ contains both v 1 and v 2 . Lemma (same object at different times) If o ♯ = β o [ ρ ]( o ) is the abstraction of some concrete object o before statement s , then o ′ ♯ = � s � o ( o ♯ ) is the abstraction of the same concrete object after statement s . � s , ρ � → ρ ′ = ⇒ � s � o ♯ ( β o [ ρ ]( o )) = β o [ ρ ′ ]( o )

  39. Analysis Soundness Theorem � s , ρ � → ρ ′ = ⇒ β ρ ( ρ ′ ) ⊑ � s � ρ ♯ ( β ρ ( ρ ))

  40. Tracematch state abstraction σ ♯ ⊆ Q × ( F → D ♯ ) with ⊑ = ⊆ where Q is set of tracematch states, F is set of tracematch parameters, D ♯ is ⊤ o ♯ o ♯ o ♯ positive bindings 3 2 1 ¬ o ♯ 1 ¬ o ♯ 2 ¬ o ♯ 3 ¬ o ♯ 1 ¬ o ♯ ¬ o ♯ 1 ¬ o ♯ ¬ o ♯ 2 ¬ o ♯ 2 3 3 negative bindings ¬ o ♯ ¬ o ♯ ¬ o ♯ 1 2 3 ⊥

  41. Tracematch state abstraction � ρ ♯ ( b ( f )) if f ∈ dom ( b ) pos ♯ ( b , ρ ♯ )( f ) = ⊥ otherwise � if f = f ′ { ρ ♯ ( b ( f )) } neg ♯ ( b , ρ ♯ , f )( f ′ ) = ⊥ otherwise � tr � a , b � � σ ♯ ( σ ♯ ) = i , m ♯ ⊔ pos ♯ ( b , ρ ♯ ) ∈ σ ♯ ∧ δ ( j , a , i ) �� � � j , m ♯ � � : ∪ i , m ♯ ⊔ neg ( b , ρ ♯ , f ) ∈ σ ♯ ∧ f ∈ dom ( b ) �� � � i , m ♯ � � :

  42. Tracematch state abstraction � O ♯ ( b ( f )) if f ∈ dom ( b ) pos ♯ ( b , O ♯ )( f ) = ⊥ otherwise � if f = f ′ { O ♯ ( b ( f )) } neg ♯ ( b , O ♯ , f )( f ′ ) = ⊥ otherwise � tr � a , b � � σ ♯ ( σ ♯ ) = � O ♯ ⊆ ρ ♯ ∧ compat( O ♯ ) i , m ♯ ⊔ pos ♯ ( b , O ♯ ) ∈ σ ♯ ∧ δ ( j , a , i ) �� � � j , m ♯ � � : ∪ i , m ♯ ⊔ neg ( b , O ♯ , f ) ∈ σ ♯ ∧ f ∈ dom ( b ) �� � � i , m ♯ � � :

  43. Tracematch state abstraction � O ♯ ( b ( f )) if f ∈ dom ( b ) pos ♯ ( b , O ♯ )( f ) = ⊥ otherwise � if f = f ′ { O ♯ ( b ( f )) } neg ♯ ( b , O ♯ , f )( f ′ ) = ⊥ otherwise � tr � a , b � � σ ♯ ( σ ♯ ) = � O ♯ ⊆ ρ ♯ ∧ compat( O ♯ ) i , m ♯ ⊔ pos ♯ ( b , O ♯ ) ∈ σ ♯ ∧ δ ( j , a , i ) �� � � j , m ♯ � � : ∪ i , m ♯ ⊔ neg ( b , O ♯ , f ) ∈ σ ♯ ∧ f ∈ dom ( b ) �� � � i , m ♯ � � : � s � σ ♯ ( σ ♯ ) = map o ♯ [ � s � o ♯ ]( σ ♯ )

  44. Tracematch state abstraction � O ♯ ( b ( f )) if f ∈ dom ( b ) pos ♯ ( b , O ♯ )( f ) = ⊥ otherwise � if f = f ′ { O ♯ ( b ( f )) } neg ♯ ( b , O ♯ , f )( f ′ ) = ⊥ otherwise � tr � a , b � � σ ♯ ( σ ♯ ) = � O ♯ ⊆ ρ ♯ ∧ compat( O ♯ ) i , m ♯ ⊔ pos ♯ ( b , O ♯ ) ∈ σ ♯ ∧ δ ( j , a , i ) �� � � j , m ♯ � � : ∪ i , m ♯ ⊔ neg ( b , O ♯ , f ) ∈ σ ♯ ∧ f ∈ dom ( b ) �� � � i , m ♯ � � : � s � σ ♯ ( σ ♯ ) = map o ♯ [ � s � o ♯ ]( σ ♯ ) What about loads from heap?

  45. Analysis Soundness Theorem � s , σ � → σ ′ = ⇒ β σ ( σ ′ ) ⊑ � s � σ ♯ ( β σ ( σ ))

  46. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { for(Iterator it = in.iterator(); it.hasNext();) { List<Integer> l = it.next(); for(Iterator it2 = in.iterator(); it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  47. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); it.hasNext();) { List<Integer> l = it.next(); for(Iterator it2 = in.iterator(); it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  48. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); for(Iterator it2 = in.iterator(); it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  49. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  50. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { Integer i = it2.next(); out.add(i); } } }

  51. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); out.add(i); } } }

  52. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); } } }

  53. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } } } }

  54. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it.hasNext();) { {{ in } , { out } , { it } } , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } } } }

  55. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� , � 1 , { l } , { it2 }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } } } }

  56. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� , � 1 , { l } , { it2 }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , {} , { it2 }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } } } }

  57. List flattening example void flat(List<List<Integer>> in, List<Integer> out) { {{ in } , { out }} , {� 0 , ⊥ , ⊥�} for(Iterator it = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } it.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 4 , { in } , { it }� , � 1 , { l } , { it2 }� } List<Integer> l = it.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , {} , { it2 }� } for(Iterator it2 = in.iterator(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� , � 1 , {} , {}� } it2.hasNext();) { {{ in } , { out } , { it } , { l } , { it2 } } , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 4 , { l } , { it2 }� } Integer i = it2.next(); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } out.add(i); {{ in } , { out } , { it } , { l } , { it2 } , { i }} , {� 0 , ⊥ , ⊥� , � 1 , { in } , { it }� , � 1 , { l } , { it2 }� } } } }

Recommend


More recommend