Using Slice Pro les and Metrics during Software Maintenance Linda M. Ott
Dept. of Computer Science Michigan Technological University Houghton, MI 49931 Email:
[email protected] Abstract Slice pro ling is a tool which was developed as an aid in determining the cohesion of a software module. Slice pro les can be used, along with slice based metrics, during the maintenance phase of a software project to facilitate understanding of the system. In this paper, we present slice pro les and some slice based metrics. We then show, through an example, ways of utilizing these tools while initially familiarizing oneself with a software system to be maintained.
1 Introduction Preserving and/or increasing the reliability of software during maintenance requires that the software engineers assigned to the system understand how the various components of the code interact. In general, maintainers of software systems were not the developers of the software and thus it is essential that they have tools which facilitate their understanding of the code and the data interactions within it. Slice pro ling is a tool which was developed as an aid in determining the cohesion of a software module. In this paper we show how these slice pro les can be used, along with slice based metrics, during the maintenance phase of a software project. These pro les and metrics can indicate quickly to a maintenance programmer beginning on a new project portions of the code that may require extra attention in order to be understood. Slice pro les can aid the maintainer in determining data interactions among modules. They may also be used to indicate inappropriate modularization which may lead to diculties during maintenance. This information can either be used to perform preventive maintenance or to aid the maintenance programmer in correctly identifying areas of the program that need to be considered when making modi cations to the code. The rst part of this paper reviews slicing and introduces a variation on slicing called metric slices. Slice pro les are then introduced. An example shows how these pro les can be used by a maintenance programmer to facilitate understanding complex code. This is followed by a discussion of the use of some slice based metrics as indicators of these more complex modules.
2 Background 2.1 Program Slicing
Slicing is a method of program reduction introduced by Weiser [18, 19, 20]. Starting from a subset of a program's behavior, called a slicing criterion, the slicing process results in a minimal form program that re ects the same subset of the program's behavior. Slices were proposed as potential debugging tools and program understanding aids. They have since been used in a broader class of applications (e.g., [1, 4, 6, 7, 8, 9, 10, 12, 16]. Slices can be de ned as follows. De nition 1. A slicing criterion is a tuple < i; V >, where i denotes a speci c statement number in a module M and V is a subset of the variables in M . De nition 2. An intramodule slice S of a module M on a slicing criterion C is any executable module with the following properties. i. S can be obtained from M by deleting zero or more statements from M. ii. For any given input, the execution behavior at all points in the slice S is the same as would be observed in the module M with respect to the variables in V at statement i. As an example, consider the module in Figure 1. There are two distinct tasks performed by the module (the computations of the sum and of the product of the rst N integers). The only relationships between the two tasks are the common input value for N and the control structure used to compute the sum and product. The module in Figure 2 was obtained with slicing criterion C = < 13; fSumN g >. Statements 8 and 11 have been deleted since they have no eect on the value computed for SumN. A slice for the product computation can be obtained using the criterion C = < 13; fProdN g >.
line 1 2 3 4 5 6 7 8 9 10 11 12 13
Statement procedure SumAndProduct( N : integer; var SumN : integer; var ProdN : integer ); var I : integer; begin SumN := 0; ProdN := 1; for I := 1 to N do begin SumN := SumN + I; ProdN := ProdN * I end end;
Figure 1: A module that computes two functions, the sum and product of the rst N integers. line 1 2 3 4 5 6 7 9 10 12 13
Statement procedure SumAndProduct( N : integer; var SumN : integer; var ProdN : integer ); var I : integer; begin SumN := 0; for I := 1 to N do begin SumN := SumN + I; end end;
Figure 2: Slice of SumAndProduct obtained with slicing criterion C = < 13; fSumN g >.
2.2 Metric Slices
Slices as originally de ned capture the \uses" relationship [5] of traditional ow analysis. In [15, 17], a new form of slicing is de ned which takes into account both \uses" and \used by" relationships of a sliced variable. The intention is to de ne slices which can be used more eectively to identify the cohesion of a module. These slices are called metric slices. Metric slices are de ned using a variation of the de nition of slices given in [11]. This de nition is based on Weiser's notion of statement relevance [20]. De nition 3 extends Weiser's notion of statement relevance to variables and De nition 4 identi es a set of relevant variables for each statement in a module. De nition 3. The variable w at Si in module M is relevant to the variable v at Sj in module M , if the value of v at Sj is dependent on the value of w at Si . De nition 4. The relevant variable set of the variable v at Si in module M is de ned as RVSi (M; v) = fw : w at Si is relevant to v at St g where St is the point just before module M terminates. After the RVSi (M; v) have been determined for each statement in M , relevant slices which capture
the \uses" relationship can be obtained using the following de nition. De nition 5. The relevant slice of the module M with respect to the variable v, RSlice(M; v), consists of all statements Si in M such that i. the execution of Si changes the value of a variable in RVSi (M,v), or ii. Si is a control statement that affects the value of a variable in RVSi (M,v). For an example of computing relevant slices using this approach see [15]. Slices containing statements that are aected by the value of a variable in the slicing criterion can be found by determining the set of all variables dependent on any variable in the slicing criterion at each statement in the module. These sets, called dependent variable sets, are used to determine statement inclusion in dependent slices which capture the \used by" relationship. De nition 6. The dependent variable set with respect to variable v at Si in module M is de ned as DVSi (M; v) = fw : w 6=v and the value of w at Si is dependent on the value of v at Si g: The dependent slice of module M with respect to v consists of all statements Si in M such that i. the execution of Si changes the value of any variable in DVSi (M; v), or ii. Si is a control statement S involving a variable in DVSi (M; v) fvg. Again for an example see [15]. RSlices represent \uses" data relationships since only relevant variables are considered as a basis for slice inclusion. DSlices are de ned in terms of dependent or \used by" data relationships. The following metric slice de nition incorporates both of these data relationships. De nition 8. A metric slice for the variable v in module M is de ned as MSlice(M; v) = RSlice (M; v) S DSlice (M; v): De nition 7.
2.2.1 Slice Pro les
Slice pro les were developed to facilitate visualizing the relationships among the slices generated for a module [14, 17]. A slice pro le for procedure SumAndProduct is given in Figure 3. The \Line" column contains the line number of each statement in the module. Each column with a variable name heading in the slice pro le corresponds to a slice of that variable using the
criterion C = < length(M ); fvariablenameg >. All rows in the pro le marked with a vertical bar \j" are statements included in a slice for a particular variable, otherwise the row is blank. The \Statement" column contains the source statement. For example, the column with heading SumN in Figure 3 corresponds to the slice for C = < 13; fSumN g >. This slice consists of all statements containing a vertical bar in the column for SumN, i.e., statements 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, and 13. In [14], it is shown how slice pro les visually indicate the cohesion level of a module. In order to do this more eectively, slices are computed on the set of variables which are outputs from the module. Also slices are restricted to what Emerson [3] calls VRES or variable-referent executable statements. These are all statements which reference a variable. (Note that when slices are restricted to VRES, they are not executable. This is not in agreement with Weiser's original de nition.) For the remainder of this paper, slice pro les will indicate metric slices based on the outputs of the module and will be restricted to VRES. As an example, consider the module in Figure 4 which computes two separate functions, the sum of the rst N numbers and the product of the rst N numbers. This can be clearly seen from the slice pro le. See [14] for further examples.
3 Using Slices during Maintenance In [4], the use of another form of slice called a decomposition slice is presented which can be used to restrict the portion of a program that a maintainer need consider when making a change. Here we focus more on the types of activities that a programmer might engage in during an initial familiarization process when assigned to a new project.
3.1 Slice Pro les
Slice pro les can be used as an aid in understanding data interactions during maintenance. In the previous discussion, we have been looking at intramodule slices. Both intramodule and intermodule slices can be used to obtain information about the code. For instance, intramodule slices can indicate the level of cohesion of a module. As an example, the slice pro le in Figure 4 is indicative of a module with low cohesion. The two slices do not overlap at all, indicating that two independent functions are being computed. If we computed a slice pro le for the module in Figure 1, we would see that the only statement which is contained in both slices is the for loop statement. Thus this module has (depending on our terminology) control [14] or procedural [2] communication. This information could be used by the maintenance programmer, if desired, to perform preventive maintenance and improve the modularity of the system. In many situations, however, when studying software during maintenance, one is interested in using intermodule slices. Intermodule slice pro les provide information about the interaction of a module with the rest of the system. They include slices on variables such as globals which are modi ed by modules
called by the one currently being examined. We compute intermodule slice pro les by extending the definitions presented earlier. (For discussion on and algorithms for computing intermodule slices based on Weiser's original de nitions see [6, 20].) For the remainder of this paper, a slice pro le for a module will indicate intermodule metric slices for all variables which are outputs of that module. Since this includes variables such as globals which are modi ed by called modules, the intermodule slice pro le can give information regarding the extent of the eects of executing a module. For instance, if an intermodule slice pro le includes a variable not local to this module, it is apparent that some called module modi es this nonlocal variable. On the other hand, if the intermodule slice pro le for a function includes only the function variable, it is clear that we have a functional module with no side-eects. Thus, we can use these intermodule slice pro les during maintenance to determine the potential eects o a change. Likewise, we can use these pro les to indicate areas of poor modularization which might be candidates for enhancement. We will illustrate the use of such slice pro les as a maintenance tool by examining a Pascal program. The program, a 500 line interpreter, was written several years ago by an experienced computer science faculty member for use in a systems software course. It is a small program by industry standards but is of sucient size to illustrate some of the ways that slice pro les can be used to aid a maintenance programmer. Like many programs currently undergoing maintenance, the concepts of data abstraction and information hiding only somewhat aected the design of this system. In some situations this was due to the language used for implementation. In others this may have occurred because these concepts were not fully appreciated or understood at the time of development. To begin the illustration we examine a simple procedure which computes just one output. See Figure 5 for the slice pro le of IntByt8. We can see from the slice pro le that IntByt8 computes exactly one output b and that the computation of b requires all statements in the procedure. Thus we have a functional module. And the maintenance programmer can quickly determine that there is no need to put undue eort into analyzing this procedure further. We now examine a larger procedure. Figure 6 contains the slice pro le for the Initialize procedure. In this slice pro le, we see that this procedure is initializing numerous global variables. The rst is an array which accounts for the one long slice. We next notice that pages and memsize are related to each other and that further down in the module, they aect the value of memory. We also see several other global variables that are initialized. It is easily observed from the slice pro le that this is a temporally cohesive module with the function of initializing the global data structures. One can also deduce from this procedure that either IntByt8 or GetByte obtains values from the input le since all calls to these modules are included in the slice on input. Figure 7 contains the slice pro le for FetchInstr, the nal example that we will examine. Here we again see a module that is aecting global variables.
Line SumN ProdN Statement 1 j j procedure SumAndProduct( N : integer; 2 j j var SumN : integer; 3 j j var ProdN : integer ); 4 j j var 5 j j I : integer; 6 j j begin 7 j SumN := 0; 8 j ProdN := 1; 9 j j for I := 1 to N do begin 10 j SumN := SumN + I; 11 j ProdN := ProdN * I 12 j j end 13 j j end; Figure 3: Slice pro le for SumAndProduct. Statements included in the slice for C =< 13; fSumN g > are indicated with a \j" in column SumN of the pro le. The slice for C =< 13; fProdN g > is indicated in column ProdN.
Line SumN Prod
1 2 3 4 5 6
j j j
j j j
Statement procedure SumAndProduct2( N : integer; var SumN : integer; var ProdN : integer ); var I : integer; begin SumN := 0; for I := 1 to N do SumN := SumN + I; ProdN := 1; for I := 1 to N do ProdN := ProdN * I end;
Figure 4: Metric slice pro le for the module SumAndProduct2 with slices restricted to VRES.
Line b 1 2 3
j j j
Statement procedure IntByt8 ( i : int8; var b : byte); var bit : 0..7; begin for bit := 7 downto 0 do begin b[bit] := (i mod 2) = 1; i := i div 2 end end;
Figure 5: Intermodule metric slice pro le for IntByt8.
Line OpTable pages input memsize memory PC SP P X A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
j
Statement procedure Initialize; var i : 0..65535; begin OpTable[ADC] := 'ADC'; OpTable[ANN] := 'ANN'; OpTable[ASL] := 'ASL'; OpTable[EOR] := 'EOR'; OpTable[LSR] := 'LSR'; OpTable[ORA] := 'ORA'; OpTable[SBC] := 'SBC'; OpTable[INX] := 'INX'; OpTable[DEX] := 'DEX'; OpTable[NOP] := 'NOP'; OpTable[PHA] := 'PHA'; OpTable[BCC] := 'BCC'; OpTable[BCS] := 'BCS'; OpTable[BNE] := 'BNE'; OpTable[BEQ] := 'BEQ'; OpTable[BRK] := 'BRK'; OpTable[CLC] := 'CLC'; OpTable[PLA] := 'PLA'; OpTable[SEC] := 'SEC'; OpTable[JMP] := 'JMP'; OpTable[JSR] := 'JSR'; OpTable[PHP] := 'PHP'; OpTable[RTS] := 'RTS'; OpTable[CMP] := 'CMP'; OpTable[CPX] := 'CPX'; OpTable[STA] := 'STA'; OpTable[LDA] := 'LDA'; OpTable[TAX] := 'TAX'; OpTable[TXA] := 'TXA'; OpTable[TSX] := 'TSX'; OpTable[TXS] := 'TXS'; OpTable[PLP] := 'PLP'; readln(pages); memsize := pages*256 - 1; IntByt8( GetByte, A ); IntByt8( GetByte, X ); IntByt8( GetByte, SP ); IntByt8( GetByte, P ); IntByt8( GetByte, PC[Hi] ); IntByt8( GetByte, PC[Lo] ); for i := 0 to memsize do IntByt8( GetByte, memory[i] ); end;
Figure 6: Intermodule metric slice pro le for module Initialize.
The output le and the global variable IR are obviously modi ed by this procedure. One global variable, MAR, is modi ed by a call to this procedure even though this is not apparent from the local code and two variables, MBR and PC are modi ed by this procedure although the procedure indicates only use of these variables. From these examples, we observe that the slice pro les allow us to see what variables are aected by a module and how tightly interrelated the module components are. Through the use of slice metrics introduced in the next section, we see a way of getting an overview of the system and of providing someone unfamiliar with the system an indication of which modules may require extra eort to understand the breadth of their eects.
3.2 Slice Metrics
In his original work on slicing, Weiser proposes several metrics. These metrics are shown to relate to module cohesion by Longworth [11] and Thuss [17]. Here we will look at a subset of the metrics studied in [17]. For notational convenience, let VM be the set of variables used by module M and let V be a subset of VM containing only those variables to be considered in the metric computations. (For the present case we are considering output variables.) The symbol SLi corresponds to the slice obtained for vi. Let SLint be the intersection of all the SLi , that is
V \ j
j
SLi : (1) i=1 The length of a module, M , denoted length(M), is the number of VRES (variable-referent executable statements) in M . Tightness, T (M ), measures the number of stateSLint =
ments included in every slice. High tightness values would seem to indicate a high degree of data relationships within the module, possibly indicating a highly functional module. TM is expressed as a ratio of the number of statements in the intersection of all the slices over the module length, that is jSLint j (2) T (M ) = length( M) Parallelism, P (M ), measures the number of slices
with few statements in common. It may re ect the number of \unrelated" processing elements within a module. PM is expressed as the number of slices having a pairwise overlap with all of the other slices less than or equal to a threshold, , that is
\
P (M ) = jfSLi such that jSLi SLj j < for all j 6= igj (3) MinCoverage, MIN(M ), measures the length of the shortest slice as a ratio to the module length. High MIN(M ) values indicate that the shortest slice requires most of the statements in the module. This
is an indication that all of the slices interact, and therefore, may indicate modular functionality. 1 (4) i jSLi j length(M ) min Values of T (M ) and MIN(M ) will range from 0 to 1, with the assumption being that higher values indicate more tightly cohesive modules. Values of P (M ) will range up from 0; in this case the higher values are assumed to indicate that the module contains multiple unrelated or only slightly related tasks. Table 1 shows the slice based metrics for each of the modules in this program. As we can see from Table 1, the program consists of many short modules. There are a total of 32 modules; all but 6 are less than 10 lines long. (Note that the length of a module is reported in this table as the number of VRES, that is variable-referent executable statements. Thus, the total of the module lengths is less than the reported length of 500 lines of code.) By examining the table, we can form several hypotheses about the program. For example in [15], we show that functionally cohesive modules tend to have metric values near or equal to 1. From Table 1, we see that many of the modules appear to be functionally cohesive modules which compute a single output. An indication of this in the table is the number of modules with a single slice and metric values all equal to 1. This conjecture can be easily veri ed by quickly examining the appropriate code. On the other hand, the table also indicates that there are several modules which may require greater eort to understand their function. For example, if we examine the metrics for FetchInstr, we see that although the module is short, i.e., it has 5 VRES statements, P (FetchInstr) has the relatively large value of 5 and the values of T (FetchInstr) and MIN(FetchInstr) are quite low. This indicates the likelihood that multiple tasks are combined in this one procedure. As we noticed above, FetchInstr does indeed perform multiple tasks, including writing to the output le and modifying several global variables. Similarly, we can deduce from the table that Initialize, as discussed above, performs operations on apparently unrelated data. In this case, examining the code shows that all the operations are similar, i.e., initializations. However, as the metrics indicate, the data operated on is unrelated. As the last example, we will look at Push. The metrics for this module may appear somewhat surprising since Push sounds like a fairly standard function which one might assume would be highly cohesive. Examining Figure 8, we see again the modi cation of global variables. In this case, the metrics have alerted us to examine a section of the code which may require greater than the anticipated amount of eort to comprehend its total eect. MIN(M ) =
4 Future Work The example presented here provides an indication that slice pro les are a useful tool in a maintenance environment. Empirically evaluating the usefulness
Line output MBR IR MAR PC 1 2 3 4 5
j j
j j
j
j j
j
j
Statement procedure FetchInstr; begin write(HighNib(PC[Hi]),LowNib(PC[Hi]),' '); write(HighNib(PC[Lo]),LowNib(PC[Lo]),': '); FetchPC; IR := MBR; write(OpTable[Decode]:3,' ') end;
Figure 7: Intermodule metric slice pro le for FetchInstr. Line MBR memory MAR SP 1 2 3 4
j
j
j
j
j j
Statement procedure Push ( b : byte ); begin MBR := b; IntWrd16( BytInt8(SP) + 256, MAR ); Store; DecByt(SP) end;
Figure 8: Intermodule metric slice pro le for Push. of a tool based on these concepts is necessary in order to determine the actual eectiveness. It would be bene cial to know under what conditions bene ts are achieved and how much bene t is actually provided to the programmer. It may be that for large systems the slice pro les are too complex to be of signi cant bene t or it may be under these conditions when programmers truly bene t. One particular advantage of this approach is that slices and the underlying data- ow analysis can be used in multiple ways in a software development and maintenance environment. Thus the cost of providing this information to a maintenance programmer should be minimal. As pointed out in [4], if the data- ow analysis necessary to compute slices is one of the deliverables from the development team to the maintenance team, then tools based on computing slices using incremental techniques can be built. This would allow quick and relatively inexpensive updates to the slicing pro ler. In addition to determining the overall usefulness of such a tool, the exact form of such a tool needs to be explored. Questions that need to be answered include: Are metric slices or Weiser's original slices more useful as an aid to overall understanding of a program? Are there sucient bene ts to justify using both intermodule and intramodule slices? On what set of variables should the slices be computed; a particular diculty which confronted us is whether this set of variables should include the input and output le variables. Another avenue of research that we are pursuing is an analytical evaluation of the metrics [13]. This analysis can provide us with a clearer understanding of what information the metrics are providing.
Acknowledgements I am grateful to the Department of Computer Science at Colorado State University for providing me with facilities and an environment that resulted in a productive sabbatical year including the completion of this paper.
References [1] J.-D. Choi, B. Miller, and P. Netzer. Techniques for debugging parallel programs. Technical Report 786, Univ. Wisconsin-Madison, 1988. [2] L. L. Constantine and E. Yourdon. Structured design. Prentice-Hall, 1979. [3] T. J. Emerson. A discriminant metric for module cohesion. In Proc. 7th International Conference on Software Engineering, pages 294{303, 1984. [4] Keith Brian Gallagher and James R. Lyle. Using program slicing in software maintenance. IEEE Trans. Software Engineering, 17(8):751{ 761, 1991. [5] Matthew S. Hecht. Flow Analysis of Computer Programs. North-Holland, 1977. [6] S. Horwitz, J. Prins, and T. Reps. Integrating non-interfering versions of programs. ACM Trans. Programming Languages and Systems, 11(3):345{386, 1989. [7] S. Horwitz, T. Reps, and D. Binkley. Interprocedural slicing using dependence graphs. ACM Trans. Programming Languages and Systems, 12(1):26{60, 1990.
Table 1: Intermodule metric slice based metrics for interpreter. v is the length of a module computed as the number of variable-referent executable statements. SL is the set of slices computed for each module. M v jSLj T MIN P BytInt8 4 1 1.00 1.00 1 IntByt8 3 1 1.00 1.00 1 WrdInt16 4 1 1.00 1.00 1 IntWrd16 3 1 1.00 1.00 1 HexInt4 3 1 1.00 1.00 1 IntHex4 3 1 1.00 1.00 1 LowNib 1 1 1.00 1.00 1 HighNib 1 1 1.00 1.00 1 IncByt 1 1 1.00 1.00 1 DecByt 1 1 1.00 1.00 1 IncWrd 1 1 1.00 1.00 1 DecWrd 1 1 1.00 1.00 1 WriteByte 1 1 1.00 1.00 1 WriteWord 3 1 1.00 1.00 1 DumpRegisters 8 1 1.00 1.00 1 Print 17 1 0.94 0.94 1 GetByte 5 2 0.00 0.40 2 Initialize 27 11 0.04 0.07 11 Fetch 1 1 1.00 1.00 1 Store 1 1 1.00 1.00 1 OpCodeError 2 1 0.50 0.50 1 Decode 44 2 0.11 0.23 2 FetchPC 3 3 0.33 0.33 1 FetchInstr 5 5 0.00 0.20 5 AddrModeError 2 1 0.50 0.50 1 AddrMode 21 2 0.14 0.24 2 FetchOpand 40 5 0.08 0.15 2 Push 4 4 0.00 0.25 4 Pop 4 4 0.00 0.25 4 Branch 5 2 0.80 0.80 0 ExecInstr 83 9 0.01 0.08 9 interpreter 9 2 0.78 0.78 0
[8] B. Korel and J. W. Laski. Dynamic program slicing. Information Processing Letters, 29(3):155{ 163, 1988. [9] B. Korel and J. W. Laski. Stad { a systerm for testing and debugging: User perspective. In Proc. 2nd Workshop on Software Testing, Veri cation and Analysis, 1988. [10] Arun Lakhotia and Jagadeesh Nandigam. Computing module cohesion. Technical Report CACS TR-91-5-4, University of Southwestern Louisiana, November 1991. [11] H. D. Longworth. Slice based program metrics. Master's thesis, Michigan Technological University, 1985. [12] H. D. Longworth, L. M. Ottenstein, and M. R. Smith. The relationship between program complexity and slice complexity during debugging tasks. In Proc. IEEE COMPSAC, pages 383{ 389, 1986. [13] Linda M. Ott and James M. Bieman. Eects of software changes on module cohesion. Technical Report CS-92-6, Dept. Computer Science, Michigan Technological Univ., March 1992. Also published as Technical Report CS-92-113 Dept. Computer Science, Colorado State Univ. [14] Linda M. Ott and Jerey J. Thuss. The relationship between slices and module cohesion. In Proc. 11th International Conference on Software Engineering, pages 198{204, 1989. [15] Linda M. Ott and Jerey J. Thuss. Slice based metrics for estimating cohesion. Technical Report CS-91-4, Dept. Computer Science, Michigan Technological Univ., November 1991. Also published as Technical Report CS-91-124 Dept. Computer Science, Colorado State Univ. [16] K. J. Ottenstein and L. M. Ottenstein. The program dependence graph in a software development environment. In Proc. ACM SIGSOFT/SIGPLAN Software Eng. Symp. on Practical Software Development Environments, 1984. See also SIGPLAN Notices, 19,5, 177-184. [17] Jerey J. Thuss. An investigation into slice based cohesion metrics. Master's thesis, Michigan Technological University, 1988. [18] M. D. Weiser. Program slicing. In Proceedings of the 5th International Conference on Software Engineering, pages 439{449, 1981. [19] M. D. Weiser. Programmers use slices when debugging. Communications of the ACM, 25(7):446{452, 1982. [20] M. D. Weiser. Program slicing. IEEE Trans. Software Engineering, 10(4):352{357, 1984.