JATO: Slicing Java Programs Hierarchically - CiteSeerX

5 downloads 129 Views 109KB Size Report
are presented, the architecture of the Java program analyzing Tool (JATO) based on ..... performance of slicing will be improved considerably. The procedure .... CLDG. MLDG. JATO software measurement tools software testing tools. GUI.
JATO: Slicing Java Programs Hierarchically Bixin Li Turku Centre for Computer Science, Åbo Akademi University, Department of Computer Science, Lemminkäisenkatu 14, FIN-20520 Turku, Finland

Xiaocong Fan Turku Centre for Computer Science, Åbo Akademi University, Department of Computer Science, Lemminkäisenkatu 14, FIN-20520 Turku, Finland

Turku Centre for Computer Science TUCS Technical Report No 416 August 2001 ISBN 952-12-0864-3 ISSN 1239-1891

Abstract Program slicing can be effectively used to debug, test, analyze, understand and maintain object-oriented software. In this paper, a new slicing model is proposed to slice Java programs based on their inherent hierarchical feature. The main idea of hierarchical slicing is to slice programs in stepwise way, from package level, to class level, method level, and finally up to statement level. Stepwise slicing algorithm and the related graph reachable algorithms are presented, the architecture of the Java program analyzing Tool (JATO) based on hierarchical slicing model is provided, and a case study is also given. Key words: program slicing, object-oriented programming, program dependence graph.

TUCS Research Group

Programming Methodology Group

1. Introduction Program slice is actually an abstraction of people’s concerns in program understanding [10,11]. Program slicing has been used in a variety of software engineering areas, such as debugging, testing, program comprehension, reverse engineering, software maintenance, software test, software metrics etc. A slice of a module at statement s with respect to variable v is the set of all statements and predicates that might affect or be affected by the value of v at s. Initially, the algorithm for computing slices is based on data flow analysis. It is suggested in [7] that program dependence graph (PDG) could be used to compute slices more efficiently and precisely. Such kind of algorithm based on program dependence graphs was presented by Horwitz, Reps, and Binkley [2], where backward slices can be obtained by walking backwards over the program dependence graphs to obtain all the nodes affecting the value of the concerned variables, and forward slices can be obtained by walking forwards over the program dependence graphs to obtain all the nodes affected by concerned variables. In traditional procedure-based programs, we mainly focus on all kinds of data-flows and control-flows in procedures or between procedures, which can be computed by graphreachable algorithms [1, 2], or two-phase graph-reachable algorithms [7]. In order to slice such kind of procedure-based programs, one must take three steps: 1) construct program dependence graphs, 2) slice program dependence graphs based on graphreachable or two phase graph-reachable algorithms and get sliced program dependence graphs, 3) obtain sliced program from sliced program dependence graph. However, things get complicated when it comes to object-oriented programs. In addition to considering all kinds of data-flows and control-flows as those in procedurebased programs, we must also consider different dependence relationships originated from the class and object concepts, such as inheritance dependency, message dependency, reference dependency, concurrency dependency, etc. So far, there are two approaches proposed to slice object-oriented programs. One can be called object-oriented extension that is based on traditional graph-reachable algorithms and two-phase graph-reachable algorithms. Many researchers have been engaging in this way. A. Krishnaswamy[3] used object-oriented program dependence graph(OPDG), an extention of system dependence graph (SDG), by embedding class hierarchy graph (CHG) into SDG. He also proposed an algorithm based on OPDG to slice C++ programs. Marry Jean Horrald etc. extended the traditional SDG by adding class dependence graph (ClDS) in computing C++ program slices. They could also compute object slices based on object dependence graph (ODG) [4, 5]. Frank Tip etc. used class hierarchy graph (CHG) to compute class hierarchy slice [9]. Christoph Steindl presented an approach to computing inter-modular slices in object-oriented program [8]. Jianjun Zhao proposed a method to compute object-oriented concurrent program slices and dynamic object-oriented program slices [12]. However, all these methods are simply based on some kinds of dependence graphs. The other promising way is to introduce new algorithms to deal with the new object-oriented challenges in slicing object-oriented programs. In this paper, we follow this approach and try to go a step further to separate our concerns in program slicing. In another

1

words, we are trying to slice programs in a stepwise way and then integrate the step results together or commit slicing in pipe-like style. The organization of this paper is as follows. A hierarchical slicing model is introduced in the next section. Different kinds of dependence graphs are discussed in section 3, and a stepwise slicing algorithm that is based on the graph-reachable algorithms is proposed in section 4. Section 5 introduces the implemented Java program analyzing tool (JATO), which is based on the hierarchical slicing model and the stepwise slicing algorithm. Section 6 makes some comparison, and section 7 concludes the paper.

2. Hierarchical Slicing Model Object-oriented systems are, in per se, designed and implemented in hierarchical ways. In addition to the variety of different layered design approaches, such as step-wise feature introduction, feature-oriented programming, the modern programming languages themselves are providing more and more mechanisms to encapsulate different level of concerns and kinds of concerns into different modules. For example, the language construct “class”, is an essential abstract mechanism provided by objectoriented programming languages. Below the class level is the set of features and methods pertinent to the set of objects this class is trying to specify; and above the class level, some programming languages provide more scope mechanisms such as packages in Java. While the hierarchical slicing model described in this paper is specific to Java, the model and related technique can be extract to cope with the software systems written in other object-oriented programming languages. By analyzing the essential of Java programming language, we find out that Java programs, which are organized in different abstraction levels, can also be analyzed and tested in a hierarchical way with respect to the corresponding levels. Generally, a Java program has an onion-like software architecture. It may be analyzed at package-level, class-level, method-level, or statement-level. From package-level to statement-level, each level exposes more implementation details than the pre-level and abstract out some details from its post-level. Statement-level. The statement-level concerns about program statements, control predicates, and different kinds of variables, such as local variables, instance variables, class variables, etc. This is the most complicated level, since different kinds of data dependency relations and control dependency relations should be covered in this level. It has been shown to be prone to errors or lack of precise, even not very hard, by starting slicing in this level all from scratch. However, it’s our exact goal to derive program slices up to the statement-level, if it will have any benefits to our future use, such as software metrics, or testing. Method-level. The method-level refers to the methods or attributes defined in a class. This level corresponds to procedures or functions in traditional procedure-based systems. There exist two kinds of relations: used-by relation between a method and the member variables referred to by the method, and procedure-call relation between the client and server methods in a method-call invocation. This level of slicing is useful in program tracing and profiling. Class-level. A Java program viewed from the class-level is composed of a set of top level classes or interfaces. In this level, there are two kinds of relations: extension relation between superclass and its subclasses, and reification relation between a class 2

and the interfaces it claims to implement. Class is the elementary building block of an object-oriented system, thus slicing in this level is crucial in extracting frameworks or design patterns from real application domains. Package-level. Java Programs are organized as sets of packages, whose naming structure is hierarchical. At package-level, we only focus on the packages and their relations, either sub-package relation, or import relation. Slicing in the package-level is not necessary but by doing so, it may attract our attention to the most concerned parts and free our efforts out of dealing with unrelated ones. Fig.1 shows the correspondence between the levels of concerns, the levels of slicing model, and the corresponding dependence graph. Dependence graph

Level of slice

Levels of concerns Package level Class level Method level Statement level

Package level dependence graph (PLDG) Class level dependence graph (CLDG) Method level dependence graph (MLDG) Statement level dependence graph (SLDG)

Package level slice Class level slice Method level slice Statement level slice

Fig.1 levels of system concerns, dependence graphs and slices The hierarchical slicing model consists of three parts: hierarchical slicing criterion, hierarchical program dependence graphs and hybrid slicing algorithms, which will be covered in this and the next two sections. First, we must define formally our ontology about hierarchical slicing criterion. Given a Java program J, by PJ, TJ, MJ, and SJ we denote the set of packages, classes or interfaces, methods (attributes), and statements defined in J, respectively. For ∀s∈SJ, by Vs we denote the variable set occurred in statement s. Vs may be empty or a singlton. For any statement s∈SJ, we can always get its enclosing method, class or interface, and package by mapping M(s), T(s), and P(s), respectively. For the declaration statement s (or the initializer) of an attribute m, M(s) is m itself. The statements that can affect a variable v may be the variable’s declaration statement, assignment statements with v as the left part, or method call statements with v as a call by reference parameter. The statements that can be affected by a variable v may be expressions with one or more occurrences of v, or method call statements with v as a parameter. We denote the set of statements affecting v as pre(v), and the set of statements affected by v as post(v). Let predicate Hv = pre(v)∪ post(v), that is, Hv(s)=true iff s∈ Hv. We say that a package p∈PJ , or a class (interface) t∈TJ, or a method m∈MJ may affect or be affected by variable set V if ∃s∈SJ,v∈V⋅P(s)=p∧Hv(s), or ∃s∈SJ,v∈V⋅T(s)=t∧Hv(s), or ∃s∈SJ,v∈V⋅M(s)=m∧Hv(s) holds. Thus, All the packages that may affect or be affected by variable set V is given by ΣP,V={p|∃s∈SJ,v∈V⋅P(s)=p∧Hv(s) }. Similarly, all the classes (interfaces) that may affect or be affected by variable set V is given by ΣT,V={t|∃s∈SJ,v∈V⋅T(s)=t∧Hv(s) }, and all the methods that may affect or be affected by variable set V is given by

3

ΣM,V={m|∃s∈SJ,v∈V⋅M(s)=m∧Hv(s) }. We also say that a variable w may affect variable set V if some statement or predicate referencing variable w may affect variable set V. Definition 1 (slicing criterion) Given program J, a slicing criterion with respect to J is a pair ξ=, where sξ∈ SJ , ψξ⊆Vsξ. To make any sense, the variable set ψξ should not be empty. Thus, in the following we assume ψξ≠∅, for any slicing criterion ξ. Definition 2 (package level slice) Given program J and a slicing criterion ξ. Package level slice of J with respect to ξ is given by ΣP,V , where V=ψξ . Definition 3 (class level slice) Given program J and a slicing criterion ξ. Class level slice of J with respect to ξ is given by ΣT,V , where V=ψξ . Definition 4 (method level slice) Given program J and a slicing criterion ξ. Method level slice of J with respect to ξ is given by ΣM,V , where V=ψξ . Definition 5 (statement level slice) Given program J and a slicing criterion ξ. Statement level slice of J with respect to ξ is given by ΣS,V={s| v∈V⋅ Hv(s)} , where V=ψξ .

3. Hierarchical dependence graphs Four kinds of dependence graphs are used in JATO: package level dependence graph (PLDG), class level dependence graph (CLDG), method level dependence graph (MLDG), and statement level dependence graph (SLDG). The construction of these dependence graphs depends on the Code Information Tree (CIT), and the symbol reference tabular (SRB), which can be obtained by JAST-- a built-in special compiler generated by lex/yacc.

CIT +name : char * +lineno : int +ntype : NodeType +datatype : char * +casttype : char * +sibling : CIT * +child[4] : CIT * +parent : CIT* +detail : CObject *

The class diagram of Code Info Tree is shown in Fig. 2. Fig.2. Code Info Tree Logically, the structure of CIT is equivalent to abstract syntax tree (AST), each yacc syntax rule has a corresponding CIT node, which stores all the useful information for later processing.

4

MemberMethod +myName : CString +myClass : CClass_info +hasBody : bool +signature : CStringArray +instantiatedClasses : CObArray +calledMethods : CObArray +localVariables : CObArray +localClasses : CObArray +modifiedMemberData : CObArray +referedMemberData : CObArray +tag : CString = "method" +getFullName()

DataDefine +myName : CString +myType : CString +myLocal : MemberMethod

MemberData +myName : CString +myType : CString +myClass : CClass_info +getFullName()

CClass_info

CObject

CUnit_info +unitName : CString +inPack : Pack_info +myClasses : CObArray +pack_Imports : CObArray +tag : CString = "unit" +addClass() +addInPackage() imports +getFullName()

+className : CString +_extends : CClass_info +_implements : CObArray +_mData : CObArray +_mMethod : CObArray +_mTypes : CObArray +tag : CString = "type" +addInterface() +addData() +addMethod() +addType() +getFullName()

consists Pack_info +packName : CString +CUnit : CObArray +tag : CString = "package" +addCUnit()

NormalClass

InnerClass

+inCUnit : CUnit_info +getFullName()

+enclosing : CObject +getFullName()

Fig.3. class diagrams of SRB

The symbol reference tabular (SRB) exhibits the kernel idea of hierarchical slicing model and plays an important role during slice generation. The information in CITs are lifted above method level, and reorganized into different levels to facilitate program slicing. The class diagrams of SRB are shown in Fig.3. The whole symbol table is just a dynamic array with type Pack_info.

3.1 Generating of Hierarchical Dependence Graphs In this section, we introduce the algorithms used to generate the hierarchical dependence graphs. All these algorithms need traversaling some parts of the CIT trees acquired by JAST.

5

A statement-level dependence graph will be derived for each member method of each class. The SLDG of member method m of class c is a pair , where SN is the node set, each of the node corresponds to a certain statement in m; and SE is the edge set. There are three kinds of dependence relationships between statements. Statement node j may data depends on node i, where variable x is declared and accessible from j. There exists sequential control dependency between a statement and its immediate last statement. And transfer control dependency occurs in conditional statements or loop statements, where the body depends on the predicate part of these statements. SE is composed of all these kinds of dependencies. Algorithm 1 Generating SLDG Input: CIT of a method Output: the statement-level dependence graph of the method in question procedure build_SLDG(CIT *aMethod) { createNode(type=”start”); createNode(type=”end”); headp=aMethod->child[0]; While headp->sibling do OnStatement(headp->sibling) procedure OnStatement (CIT *aStatement) { case statement_type of simple_state: declare_state: setup_dependence (createNode(type=”simple”)); if_else_state: { setup_dependence (createNode(type=”start”)); setup_dependence (createNode(type=”predica”)); setup_dependence (createNode(type=”end”)); build_CDG (if_part); build_CDG (else_part); }

for_state: { setup_dependence ( createNode(type=”start”)); setup_dependence (createNode(type=”predica”)); setup_dependence ( createNode(type=”end”)); build_CDG (loop_body ); } call_state: { getDependence(formal_parameter); setup_dependence ( createNode(type=”call”)); } …… } procedure setup_dependence(Node *aNode ) { build_DataDependency(aNode); build_SequentialControlDependency(aNode); if (aNode->parent is loop_statement) or if (aNode->parent is switch_statement) or if (aNode->parent is cond_statement) PredNode=get_predicate(aNode->parent); build_CDependency(aNode, PredNode); }

Fig.4 Generating SLDG Algorithm2 Generating MLDG A method-level dependence graph will be derived for each class. There are two kinds of dependency between member variables and member functions: used-by relation between a method and the member variables accessed by the method, and calling relation between a method and the methods (may belong to the other classes) that are called from within the method. The MLDG of class c is a 2-dimension array MAc, where the length of each dimension is the total number of member variables and methods, MemCount. MAc[i, j]=1 means that the member function denoted by j accesses the member variable denoted by i, and MAc[i, j]=2 means that the member function denoted by j calls the member function denoted by i. 6

Input: CIT of a class Output: the method level dependence graph MA of the input class procedure build_MLDG(CIT *aClass) { class_info=aClass->detail; for( int i = 0; i < class_info->_mMethod.GetSize();i++ ) { member=class_info->_mMethod .GetAt(i); MAUpdate(MA, member->modifiedMemberData, 1); MAUpdate(MA, member-> referedMemberData, 1); MAUpdate(MA, member->calledMethods, 2); } } Fig.5 Generating MLDG Algorithm3 Generating CLDG In CLDG, we focus on all the classes and interfaces and the relations among them. There are 6 kinds of dependency between classes (interfaces): extending, implementing, class-level association, inner-classing, method-level association (local variable), and local-classing. A CLDG is a 2-dimension array CA, where the length of each dimension is the total number of classes and interfaces, ClassCount. CA[i, j]=1 means that the Input: CIT of a system Output: class level dependence graph CA procedure build_CLDG(CIT *aSystem) Accessed={}; for all Pack_info pi in aSystem for all ui in pi.CUnit for all ci in ui.myClasses if ci not in Accessed Accessed.append(ci) CAUpdate(CA, ci, ci ->_extends, 1); CAUpdate(CA, ci, ci ->_implements, 2); CAUpdate(CA, ci, ci ->_mTypes, 4); for( int i = 0; i < ci ->_mData.GetSize();i++ ) iData= strip_rear_dims(ci ->_mData .GetAt(i)); if (iData is not a primitive type) CAUpdate(CA, ci, ci -> iData, 3); for( int i = 0; i < ci ->_mMethod.GetSize();i++ ) iClass= ci ->_mMethod .GetAt(i)->instantiatedClasses; CAUpdate(CA, ci, ci ->iClass, 5); 7 iLClass= ci ->_mMethod .GetAt(i)->localClasses; CAUpdate(CA, ci, ci ->iLClass, 6); Fig.6 Generating CLDG

class (interface) denoted by i immediately inherits the class (interface) denoted by j; CA[i, j]=2 means that the class denoted by i implements the class denoted by j; CA[i, j]=3 means that the class denoted by i has a member data with class j as its type; CA[i, j]=4 means that the class denoted by i has declared an inner class j; CA[i, j]=5 means that the class denoted by i has declared a local variable with type j in some of its method; and CA[i, j]=6 means that the class denoted by i has declared an inner class j in some of its method. Algorithm4 Generating PLDG Only packages and sub-packages are concerned in PLDG. There are 2 kinds of dependency between packages: importing, and sub-packaging. Likewise, a PLDG is a 2-dimension array PA, where the length of each dimension is the total number of packages and sub-packages, PackageCount. PA[i, j]=1 means that the package i imports package j; and PA[i, j]=2 means that the package i is a sub-package of package j.

Input: CIT of a system Output: package level dependence graph PA procedure build_PLDG(CIT *aSystem) Accessed={}; for all Pack_info pi in aSystem for all ui in pi.CUnit if ui not in Accessed Accessed.append(ui) PAUpdate(PA, ui ->inPack, ui ->pack_Imports, 1); PAUpdate(PA, ui ->inPack, prefix_by_dot(ui ->inPack ), 2); Fig.7 Generating PLDG

4. Stepwise Slicing Based on the hierarchical slicing model and the different kinds of graph generating algorithms, we can introduce a stepwise slicing algorithm for slicing Java programs. The algorithm of stepwise program slicing is shown in Fig. 8. The procedure PackageSlicing() is used to get the package level slicing of , by taking the PLDG of the system in question and the slicing criterion as parameters, and returning all the packages (or sub-packages) relevant to the package enclosing statement s, i.e. P(s). Since all the irrelevant packages are cleared out of the following focus, the overall performance of slicing will be improved considerably. The procedure ClassSlicing() is used to compute the class level slicing, by taking the CLDG, slicing criterion, and the set of pertinent packages as parameters, and returning all the classes or interfaces relevant to the class enclosing statement s, i.e. C(s). The slicing focus is further zoomed in to leave all the irrelevant classes or interfaces out of consider.

8

Then, procedure MethodSlicing() is used to further determining all the member methods and member variables which are relevant to the method enclosing statement s, i.e. M(s), within every relevant class. Likewise, MethodSlicing() returns all the pertinent methods (variables) and leave the others untouched. Procedure StateSlicing() comes to our final goal, where all statements and control predicates, which affect or affected by the variables in variables set V, within every relevant method are returned as a pointer to a CIT node. The way we get the statement level slicing is a top-down, instead of a bottom-up method. This kind of stepwise slicing approach is based on the hierarchical feature of Java programs, and has been shown in JATO to be an effective and efficient solution to Java program slicing. We will give a case study in the next section. Input: slicing criterion Output: program slicing procedure CIT * OnSlicling (PLDG *pa, CLDG *ca, SliceCriteron *sc) PS=PackageSlicing(pa, P(sc->statement)); CS=ClassSlicing(ca, C(sc->statement), PS); MGS={}; for all class cc in CS do MGS = MGS.append(getMLDG(cc)); MS=MethodSlicing(MGS, M(sc->statement)); SGS={}; for all method mm in MS do SGS = SGS.append(getSLDG(mm)); SS=StateSlicing(SGS, sc->VarSet); return SS; Fig. 8 Stepwise program slicing algorithm Each of the procedures, PackageSlicing(), ClassSlicing(), MethodSlicing() and StsteSlicing(), is actually a graph reachable algorithm. They have almost the same recursion patterns where the respective DAG is traversed along the direction of edges and all the reachable nodes are marked as accessed, which are all that we need in generating program slicing. For simplicity, we only give the algorithm for package slicing, the others are almost the same. Input: package level dependence graph, slicing criterion Output: package level slicing procedure PackageSlicling (PLDG *pa, PNode *node) if (node is not in pa->marked) then pa->mark(node); result.append(node); for all nexton in pa->nextme(node) do PackageSlicing(pa, nexton); Fig.9 Package level slicing We give the informal correctness proof of the stepwise slicing algorithm OnSlicing() as follows. Since the result of package-level (class-level, method-level, statement-level) 9

slicing is a set of packages (classes, methods, statements), to facilitate the reasoning, we take them all as from the same level--statement-level. Thus, the result of package-level slicing of Java program J is no longer a set of packages, but is composed of all the statements occurred in such packages. The same goes for the result of class-level and method-level slicing. Stated as such, we can override the subset operator ⊆, and say {p1, p2}⊆J, in the meaning that the set of statements occurred in p1 or p2 is just a part of Java program J. Given program J and a slicing criterion , by procedure PackageSlicing(), we get the set of relevant packages PS, which is a subset of PJ, thus, PS⊆J holds obviously. Since ClassSlicing() is carried out only for the classes defined in packages in PS, CS⊆PS holds, too. Similarly, we have MS⊆CS, and SS⊆MS. Thus, the correctness of OnSlicing() reduces to the correctness of the different-level slicing procedures, which are classic graph reachable algorithms and correct obviously. The only different thing is that the semantics of the graphs correspond to different levels of program pieces or constructs, which are built upon CIT and SRB information derived from Java programs, and they depends on the correctness of lex/yacc, which is beyond of the scope of this paper.

5. JATO—A Java Program Analyzing Tool A Java program Analyzing TOol (JATO) has been implemented based on hierarchical slicing model in C++. JATO can construct different dependence graphs and compute program slices at different levels. The main goal of JPAT is to be integrated into a Software Quality Measurement platform as an embedded system, where program slices of Java programs at different abstract level can be measured, tested, and compared in the same environment. GUI software measurement tools

SRB trees

software testing tools graph reachable algorithm

PLDG CLDG

CIT trees

MLDG stepwise slicing

SLDG

JATO

program slices library

JAST

Java program

slicing criterion

Fig.10 JATO architecture and its embedding environment

5.1 The Architecture of JATO The architecture of JATO and its embedding environment is shown in Fig.10. JATO expects Java project files (deployment of packages) as its input. JAST is responsible for generating the Abstract Syntax trees for the input syntactically correct Java programs, 10

and SRB trees are generated by SRB generator. Then, different dependence graphs are derived and feed to graph reachable algorithms and stepwise slicing algorithm to produce the desired program slices. Measurement and test tools provide some basic tools such as coupling measurement tools, cohesion measurement tools, test tools, etc. Users can get different level slices and measurement or test results by interacting with the GUI.

5.2. A Case Study in JATO We show the hierarchical slicing approach underpinning JATO by slicing the Java program shown in Fig.11 step by step. 1. class A{ 2. public in x; 3. public f1( ) 4. { x=1;} } 5. class B extends A{ 6. public int y; 7. public f1( ) 8. {x=2;} 9. public f2( ) 10. {x=3;} } 11. class C extends A{ 12. public int y;

13. public f1( ) 14. {x=y;} } 15. class D{ 16. public void f3(A a) 17. {a.f1( ); 18. return; } } 19. class E{ 20. public static void main(String str[]){ 21. A a1=new B( ); 22. D d1=new D( ); 23. d1.f3(al); }} Fig. 11 A simple Java program

All of the dependence graphs can be acquired by traversing the concerned CIT and SRB trees. Fig.12 is the CLDG of the example program, where there is an inheritance edge from B to A, and from C to A. Since class E creates both an object of class B and class D respectively, there is a bi-directional arrow between class E and B, and so is between E and D. Fig.13 is the MLDG of the example program, where the method f1 inherited by class B and class C from class A is overridden class B and class C respectively. A A

D

E

C f1

C

B

D

f1

x

f3

a

x B

y f1

Fig. 12 The CLDG of the sample program f2

E

x

main

str

y

Fig.13 The MLDG of the sample program

Suppose we input a slicing criterion . Since statement 23 belongs to main method, and belongs to class E, method level slicing criterion is , and class

11

level slicing criterion is . Assume that all these classes belong to a package named P, then package level slicing criterion is . In order to get slice at package level, we start from the node that represents package P, find all nodes whose import edges directly or indirectly arrive P node. The set of all these nodes is package level slice of the Java program with respect to slicing criterion . In the above example, the package level slice is P itself because only one package is in question. In order to get class level slice, we firstly eliminate irrelevant nodes from CLDG based on package level slice, then from the class enclosing the slicing interest point, statement 23, figure out the set Ι composed of all nodes that can be reached from class node E along creation edges, and find the set ΙΙ of all nodes which can be reached from every class node in set Ι along inheritance or implement edges. The union of Ι and ΙΙ is the class level slice with respect to slicing criterion . Here, Ι ={B, D, E}, ΙΙ ={A}, thus the class level slice with respect to slicing criterion is {B, D, C, A}. To get the method level slice, we first eliminate irrelevant method nodes and variable nodes of class C and A from MLDG based on class level slice set {B, D, C, A}. Then traverse backward from f3 node of D along defining edges, we get node a of D. Then traverse backward from nodes a of D and x of B along used-by edges, we get nodes f1 of B and main. Thus, the method level slice is {main, D_f3, B_f1, D_a, B_x}. By eliminating all the irrelevant statements from SLDG based on method level slice set {main, D_f3, B_f1, D_a, B_x}, we get the statement level slice that is shown in Fig.14. 1. class A{ 2. public in x; } 5. class B extends A{ 6. public int y; 7. public f1( ) 8. {x=2;} } 15. class D{ 16. public void f3(A a)

17. {a.f1( ); 18. return; } } 19. class E{ 20. public static void main(String str[]){ 21. A a1=new B( ); 22. D d1=new D( ); 23. d1.f3(al); }}

Fig.14. The resulting statement level slicing of

6. Comparisons 6.1 Complexity of the slicing algorithm Compared with the traditional approaches [1,2,3], the hierarchical slicing model might have reduced the complexity of the slicing algorithm, since the different dependence graphs, i.e. PLDG, CLDG, MLDG, and SLDG, can be constructed one upon another. If a slicing criterion is specified, PLDG can be constructed by only considering the packages relevant to the slicing criterion, and leaving the other irrelevant packages out of focus. Thus, the construction time of PLDG with respect to this slicing criterion will decrease. For the same reason, the construction time of CLDG, MLDG, and SLDG with respect to this slicing criterion will decrease considerably. However, this is under the assumption that the slicing criterion specified by users is unchangeable, or at least is not changed so frequently. If there are lots of slicing criteria to be specified, the overall performance will get worse since every time a slicing criterion is input, all the dependence graphs, which depend on the slicing criterion, must be re-constructed accordingly. 12

To overcome this, we must construct these dependence graphs completely, once and for all, for every input Java project. Such pre-computed results can be reused for all the slicing criteria selected from the source program. In this way, the construction of SLDG will have the same complexity as those of the traditional approaches [1,2,3]. While, because of the larger granularity, the construction of PLDG, CLDG, and MLDG will have much less complexity than that of SLDG. Thus, the complexity of the slicing algorithm is getting a little increased for a single slicing criterion. But, in the long run, the overall performance of the slicing system will be improved considerably, since the reuse of the pre-computed dependence graphs. According to [4], the main factors affecting slicing algorithms include: V (the maximum number of predicates and assignments in a single method), P (maximum number of formal parameters in a single method), G (the number of global variables), I (maximum number of instances of a class), C (maximum number of calls made in a method), T (the maximum depth of the inheritance trees), M (the number of methods in a system), etc. For any method m, If we let PV (m)=P + G + I, then the size of m is given by size(m)=O(V+C*(1+T*(2*PV (m)))+2*PV (m)). Then the size of the system dependence graph SDG is: size(SDG)=O(size(m)*M). Since in our hierarchical slicing model, all the irrelevant packages, classes, methods are out of consideration in getting the statement level slicing, the actual number of methods need considering is much less than M, so the size of the hierarchical dependence graph HDG is much less than size(SDG). In [3], object-oriented program dependence graphs (OPDG) were introduced in slicing C++ programs. The complexity of OPDG has not been discussed, and thus incomparable. 6.2 Exactness of slice results One of the main concerns of program slicing is the exactness of the slice results. One can always get a piece of program and claim that it’s just the slice result of the given slicing criterion. However, better program understanding can only be derived from more precise slice results. In previous work, the solutions to slice programs with polymorphism are very weak, especially for polymorphic object parameters. A method was proposed to slice programs with polymorphism in [6], but the slice results are not so exact. It might include the methods in class C or A if we compute the slice with respect to slicing criterion by using their method. The hierarchical slicing model proposed in this paper can eliminate irrelevant classes or methods at class slicing level or method slicing level, so, more precise slice results can be acquired.

7. Conclusion The concept of class hierarchy slice was introduced in [9]. This idea was further extended in the hierarchical slicing model [5], which covers the package level, method level, in addition to the class level and statement level. In this model, program slices can be derived at different levels with different granularity in a stepwise way. In this paper, the hierarchical slicing model is further elaborated and refined. The prototype tool JATO has been implemented based on hierarchical slicing model to slice Java programs. One of the aims of JATO project is to be used to measure and test Java programs by using object-oriented program slicing technique. The slice results acquired 13

from JATO can be further exploited in tools concerning about software metrics, software test, etc. Currently, slice results can be generated correctly by the stepwise slicing algorithm based on the hierarchical slicing model. But, as far as the exactness of slice results is concerned, the minimal slice results can not be guaranteed in our approach, even though it’s the better one in most cases to the best of our knowledge. To find minimal slice generating algorithms based on the hierarchical slicing model is still left as our future work.

Reference [1] Horwitz, S B and Thomas, W R. The use of program dependence graphs in software engineering. In Proceedings of the Fourteenth International Conference on Software Engineering, Melbourne, Australia, May 1992. [2] Horwitz, S B, Thomas, W R., and David, B. Interprocedural slicing using dependence graphs, ACM SIGPLAN Notices, 23(1988) 35-46. [3] Krishnaswamy, A. Program Slicing: An Application of Object-Oriented Program Dependency Graphs, Technical Report TR94-108, Department of Computer Science, Clemson University, 1994. [4] Larsen, L and Harrold, M J. Slicing object-oriented software. In 18th International Conference on Software Engineering, March, 1996, 495-505. [5] LI, B. Program slicing techniques and its application in object-oriented software metrics and software test. Ph.D thesis, Nanjing University, P.R.China, Dec. 2000. [6] Liang, D and Harrold, M J. Slicing objects using system dependence graphs. In Proceedings of the 1998 International Conference on Software Maintenance, November 1998, 358-367. [7] Ottenstein, K J and Ottenstein, L M. The program dependence graph in a software development environment. In Proceedings of the ACM SIGSOFT/ SIGPLAN Software Engineering Symposium on Practical Software Development Environments, volume 19(5) of ACM SIGPLAN Notices, 1984, 177-184. [8] Steindl, C. Intermodular slicing of object-oriented programs. In International Conference on Compiler Construction (CC'98), 1998. [9] Tip, F, Choi, J D, Field, J and Ramalingham G. Slicing class hierarchies in C++. In Proceedings of the Eleventh Annual Conference on Object-Oriented Programming Systems, Languages, and Applications (OOPSLA'96), (San Jose, CA, October 6--10, 1996) 179--197. [10] Weiser, M. Program slicing. In proceedings of the 5th International Conference on Software Engineering, IEEE, 1982, 439-449. [11] Weiser, M. Program slicing. IEEE Transactions on Software Engineering, 10(1984) 352-357. [12] Zhao, J. Dynamic slicing of object-oriented programs. Technical Report SE-98119, Information Processing Society of Japan (IPSJ), May 1998

14

Turku Centre for Computer Science Lemminkäisenkatu 14 FIN-20520 Turku Finland http://www.tucs.abo.fi/

University of Turku • Department of Mathematical Sciences

Åbo Akademi University • Department of Computer Science • Institute for Advanced Management Systems Research

Turku School of Economics and Business Administration • Institute of Information Systems Science

Suggest Documents