Universidade Federal de Pernambuco
Centro de Informatica
Pos-graduacao em Ciencia da Computacao
OPTIMIZING ASPECTJ FOR JAVA ME
SOFTWARE PRODUCT LINES
Fernando Henrique Calheiros Lopes
DISSERTACAO DE MESTRADO
Recife
25 de Fevereiro de 2011
Universidade Federal de Pernambuco
Centro de Informatica
Fernando Henrique Calheiros Lopes
OPTIMIZING ASPECTJ FOR JAVA ME SOFTWARE PRODUCT
LINES
Trabalho apresentado ao Programa de Pos-graduacao em
Ciencia da Computacao do Centro de Informatica da Uni-
versidade Federal de Pernambuco como requisito parcial
para obtencao do grau de Mestre em Ciencia da Com-
putacao.
Orientador: Prof. Dr. Paulo Henrique Monteiro Borba
Recife
25 de Fevereiro de 2011
Catalogação na fonte Bibliotecária Jane Souto Maior, CRB4-571 Lopes, Fernando Henrique Calheiros Optimizing AspectJ for Java ME Software Product Lines / Fernando Henrique Calheiros Lopes - Recife: O Autor, 2011. xx, 93 p. : il., fig., tab. Orientador: Paulo Henrique Monteiro Borba. Dissertação (mestrado) Universidade Federal de Pernambuco. CIn. Ciência da Computação, 2011. Inclui bibliografia. 1. Linguagem de programação. 2. Compiladores. 3. Otimização. I. Borba, Paulo Henrique Monteiro (orientador). II. Título. 005.1 CDD (22. ed.) MEI2011 – 070
A minha famılia
AGRADECIMENTOS
“... se isso lhe serve de consolacao, que se antes de cada acto nosso nos
pusessemos a prever todas as consequencias dele, a pensar nelas a serio,
primeiro as imediatas, depois as provaveis, depois as possıveis, depois as
imaginaveis, nao chegarıamos sequer a mover-nos de onde o primeiro
pensamento nos tivesse feito parar.”
—JOSE SARAMAGO
Esse trabalho marca o fim da minha segunda jornada academica e uma das fases mais
importantes da minha vida. Aproveito esse espaco para agradecer a todos que, direta ou
indiretamente, contribuıram com essa jornada.
A minha famılia, que, apesar de distante, sempre me apoiou. Em especial, ao meu
pai, por todas as dificuldades que ele tem passado.
A Alexandra, por tudo que fez por mim durante todos os anos que estivemos juntos.
Por todo o apoio, carinho, paciencia, compreensao e por sempre ter estado comigo durante
toda essa jornada. Sem o seu apoio eu nao teria conseguido realizar esse trabalho. Ti
amo, cara mia!
Ao professor Paulo Borba, pela paciencia (muita!) e pela excelente orientacao que
tornou esse trabalho possıvel.
A todos os meus amigos, os proximos e os distantes, que me apoiaram nessa jornada.
Em especial, a Cynthia pela amizade, apoio moral e revisoes.
A todos que contribuıram de alguma forma para a elaboracao deste trabalho. Em
especial, a Marcio pela revisao de extrema valia.
A todos que fazem o Centro de Informatica da UFPE, professores, funcionarios e aos
meus colegas de trabalho do Projeto Samsung.
vi
“If there were in the world today any large number of people who desired
their own happiness more than they desired the unhappiness of others,
we could have paradise in a few years.”
—BERTRAND RUSSELL
RESUMO
Linhas de Produtos de Software (LPS) sao definidas como conjuntos de sistemas de soft-
ware que atendem a um mercado especıfico, que compartilham caracterısticas em comum,
porem sendo suficientemente distintos entre si, e que sao desenvolvidos a partir de um
conjunto de artefatos reusaveis. Entre os benefıcios possıveis com a implantacao de LPS
podemos citar o reuso em larga escala e o aumento de produtividade. Um fator-chave no
desenvolvimento de uma LPS e o mecanismo utilizado para a estruturacao de variacoes
no codigo fonte. Uma das tecnicas mais comumente utilizadas para a estruturacao de
variacoes de codigo e a compilacao condicional, tambem chamada de pre-processamento.
Apesar de ser amplamente utilizada, o uso de compilacao condicional incorre em proble-
mas de legibilidade, modularidade, manutenibilidade e qualidade.
Programacao Orientada a Aspectos (POA) e uma alternativa a compilacao condi-
cional para a estruturacao de variacoes de codigo em LPS, podendo apresentar melhor
legibilidade, modularidade, manutenibilidade, qualidade, entre outros fatores, do que a
compilacao condicional. Entretanto, o uso de AspectJ, implementacao mais popular de
POA sobre a linguagem Java, como mecanismo de estruturacao de variacoes gera um
overhead (aumento) sobre o tamanho final do codigo compilado. No contexto de LPS
de sistemas para plataformas em dispositivos moveis, em plataformas como Java ME,
que possuem restricoes de memoria, esse overhead pode tornar inviavel o uso do produto
final.
Neste trabalho, analisamos o impacto do uso de AspectJ como mecanismo de estru-
turacao de variacoes sobre o tamanho do codigo compilado e investigamos os motivos por
tras deste aumento. Para tal, utilizamos o BestLap e o Juggling, duas LPS de jogos para
dispositivos Java ME que possuem uma versao puramente pre-processada e uma versao
hıbrida, que utiliza pre-processamento e AspectJ. Utilizamos o BestLap na analise de
tamanho para quantificar o overhead com dois compiladores AspectJ, o ajc e o abc.
Em seguida, analisamos o codigo compilado de um subconjunto das construcoes As-
viii
RESUMO ix
pectJ, a fim de identificar quais construcoes geram overhead no tamanho do codigo com-
pilado e os motivos por tras deste overhead. Esse subconjunto consistiu de todas as
construcoes AspectJ utilizadas na versao hıbrida do BestLap e do Juggling, o ultimo
utilizado apenas para a elicitacao das construcoes analisadas.
Com base nessa investigacao, desenvolvemos quatro otimizacoes para o compilador abc
que modificam o codigo compilado de certas construcoes visando a eliminar o overhead.
Apresentamos detalhes da implementacao e discutimos as pre-condicoes e a corretude das
otimizacoes desenvolvidas. Em seguida, apresentamos o resultado da aplicacao destas
otimizacoes em duas LPS e discutimos como implementacoes diferentes, porem equiva-
lentes, da mesma variacao em AspectJ podem inviabilizar a aplicacao das otimizacoes.
Por fim, para garantir que as modificacoes realizadas pelas otimizacoes nao prejudiquem o
desempenho, apresentamos o resultado de testes de desempenho realizados em programas
AspectJ usados em benchmarks apos a aplicacao das nossas otimizacoes.
Palavras-chave: Java ME, Linhas de Produtos de Software, AspectJ, Programacao
Orientada a Aspectos, Compiladores, Otimizacao
ABSTRACT
Software Product Lines (SPL) are defined as sets of software systems that satisfy the needs
of a particular market, share a common set of characteristics, being, however, sufficiently
distinct among each other, and developed from a set of reusable artifacts. Among the
possible benefits of using SPL we can cite large scale reuse and productivity increase. A
key factor in the development of a SPL is the mechanism used to structure source code
variations. One of the most commonly used techniques for structuring code variations is
conditional compilation, also called preprocessing. Despite being widely used, conditional
compilation incurs in problems of legilibility, modularity, maintenability and quality.
Aspect-Oriente Programming (AOP) is an alternative to conditional compilation for
structuring code variations in SPL that can present better legilibility, modularity, main-
tenability and quality, among other factors, than conditional compilation. However, the
use of AspectJ, the most popular AOP implementation over the Java language, as a vari-
ation structuring mechanism leads to a size overhead in the final compiled code. In the
context of SPLs for mobile devices, with platforms such as Java ME, which have strict
memory requirements, this overhead can make the final product unviable for release.
In this work, we analyze the impact of using AspectJ as a variation structuring mech-
anism over the size of compiled code and investigate the motives behind this increase.
For such, we use BestLap and Juggling, two SPLs of games for Java ME devices that have
a purely preprocessed version and a hybrid version, with preprocessing and AspectJ. We
used BestLap in the size analysis to quantify this overhead with two AspectJ compilers,
ajc and abc.
Next, we analyze the compiled code of a subset of AspectJ constructs, in order to
identify which constructs generate overhead in the compiled code and the reasons behind
this overhead. This subset consisted of all AspectJ constructs used in the hybrid version
of BestLap and Juggling, the latter used only for eliciting the list of constructs.
Based on this investigation, we developed four optimizations for the abc compiler that
x
ABSTRACT xi
modify the compiled code of certain constructs with the objective of eliminating the over-
head. We present implementation details and discuss the preconditions and correctness
of the optimizations developed. Next, we present the result of the application of these
optimizations in two SPLs and discuss how different, albeit equivalent, implementations
of the same variation in AspectJ can make it inviable to apply our optimizations. Finally,
in order to ensure that the modifications realized by our optimizations do not decrease
performance, we present the results of performance tests executed in AspectJ benchmark
programs after the application of our optimizations.
Keywords: Java ME, Software Product Lines, AspectJ, Aspect-oriented Programming,
Compilers, Optimization
CONTENTS
Chapter 1—Introduction 1
1.1 Summary of Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 2—Background 5
2.1 Software Product Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1 Commonalities and Variabilities . . . . . . . . . . . . . . . . . . . 6
2.2 Conditional Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Aspect-Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.1 Pointcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3.2 Advice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.3 Inter-type Declarations . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.4 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3.4.1 ajc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3.4.2 abc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Chapter 3—Analyzing the problem 12
3.1 Size Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 AspectJ constructions inspection . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1 Aspect Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2.2 Inter-type Field Declarations . . . . . . . . . . . . . . . . . . . . . 22
3.2.2.1 Unitialized . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.2.2.2 Initialized . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2.2.3 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . 25
xii
CONTENTS xiii
3.2.3 Class Extension Inter-type Declaration . . . . . . . . . . . . . . . 28
3.2.4 Interface Implementation Inter-type Declaration . . . . . . . . . . 28
3.2.5 Inter-type Method Declaration . . . . . . . . . . . . . . . . . . . . 30
3.2.6 Advices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2.6.1 Access to private fields . . . . . . . . . . . . . . . . . . . 33
3.2.6.2 After . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.6.3 Before . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.2.6.4 Around . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Chapter 4—Optimizations 44
4.1 Inlining Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.2 Unnecessary aspectOf() Remover . . . . . . . . . . . . . . . . . . . . . . 47
4.2.1 Applying the optimization . . . . . . . . . . . . . . . . . . . . . . 52
4.2.2 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.3 Inter-type Field Initialization Inliner . . . . . . . . . . . . . . . . . . . . 53
4.3.1 Applying the optimization . . . . . . . . . . . . . . . . . . . . . . 55
4.3.2 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.4 Inter-type Method Inliner . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.4.1 Applying the optimization . . . . . . . . . . . . . . . . . . . . . . 59
4.4.2 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.5 Accessor Inliner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.5.1 Applying the optimization . . . . . . . . . . . . . . . . . . . . . . 65
4.5.2 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Chapter 5—Evaluation 69
5.1 BestLap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2 MobileMedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
5.3 Performance benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Chapter 6—Conclusion 85
6.1 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
CONTENTS xiv
6.1.1 AspectJ in Software Product Lines . . . . . . . . . . . . . . . . . 86
6.1.2 AspectJ Optimizations . . . . . . . . . . . . . . . . . . . . . . . . 87
6.2 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
6.3 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
LIST OF FIGURES
3.1 BestLap build process . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2 Box plot of the original version of the product line . . . . . . . . . . . . . 16
3.3 Box plot of the original version and the hybrid version . . . . . . . . . . 18
4.1 Modified BestLap build process . . . . . . . . . . . . . . . . . . . . . . . 45
5.1 Feature Model of the BestLap Product Line . . . . . . . . . . . . . . . . 70
5.2 Box plot of the original, hybrid and optimized versions of the BestLap
product line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
5.3 Feature Model of the MobileMedia Product Line . . . . . . . . . . . . . . 75
5.4 Box plot of the original, hybrid and optimized versions of the MobileMedia
SPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
xv
LIST OF TABLES
3.1 Comparison (in bytes) of the original version of the product line . . . . . 15
3.2 Comparison (in bytes) of the original version against the hybrid version . 17
5.1 Comparison (in bytes) of the original version of BestLap against the aspects
version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.2 Number of optimizations applications in the hybrid version of BestLap . 74
5.3 Optional and Alternative Features enabled in MobileMedia’s instances . . 79
5.4 Comparison (in bytes) of the original version of MobileMedia against the
aspects version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.5 Number of optimizations applications in the AspectJ version of MobileMedia 82
5.6 Applications of the optimizations in the benchmark programs . . . . . . 83
5.7 Execution time for the benchmarks . . . . . . . . . . . . . . . . . . . . . 84
xvi
LIST OF ALGORITHMS
1 Generic Inliner Algorithm. . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2 Unnecessary aspectOf() remover algorithm. . . . . . . . . . . . . . . . . . 50
3 Inter-type field initialization inliner algorithm. . . . . . . . . . . . . . . . . 54
4 Inter-type method inliner algorithm. . . . . . . . . . . . . . . . . . . . . . 59
5 Accessor inliner algorithm. . . . . . . . . . . . . . . . . . . . . . . . . . . 64
xvii
LISTINGS
2.1 Conditional Compilation example. . . . . . . . . . . . . . . . . . . . . . . 7
2.2 AspectJ structuring the Nokia canvas variation. . . . . . . . . . . . . . . 8
2.3 AspectJ structuring the MIDP2 canvas variation. . . . . . . . . . . . . . 8
2.4 Class affected by before execution. . . . . . . . . . . . . . . . . . . . . . . 10
2.5 Aspect with before execution advice. . . . . . . . . . . . . . . . . . . . . 10
3.1 Blank Aspect. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.2 Code generated by ajc for a blank aspect. . . . . . . . . . . . . . . . . . 20
3.3 Code generated by abc for a blank aspect. . . . . . . . . . . . . . . . . . 21
3.4 Unitialized inter-type field declaration example. . . . . . . . . . . . . . . 22
3.5 Decompiled bytecode of the class after unitialized field insertion (ajc). . . 23
3.6 Decompiled bytecode of the field initialization method and dispatchers (ajc) 23
3.7 Decompiled bytecode of the class after unitialized field insertion (abc). . . 23
3.8 Initialized inter-type field declaration example. . . . . . . . . . . . . . . . 24
3.9 Decompiled bytecode of the field initialization method (ajc). . . . . . . . 24
3.10 Decompiled bytecode of the class after initialized field insertion (abc). . . 25
3.11 Inter-type field initialization methods (abc). . . . . . . . . . . . . . . . . 25
3.12 Trying to add a constant with a inter-type field declaration . . . . . . . . 26
3.13 Failed attempt of constant insertion (ajc) . . . . . . . . . . . . . . . . . . 26
3.14 Failed attempt of constant insertion (abc) . . . . . . . . . . . . . . . . . 26
3.15 Class where a constant is being inserted . . . . . . . . . . . . . . . . . . 27
3.16 Constant declaration through interface implementation inter-type declara-
tion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.17 Decompiled bytecode of constant() method (ajc). . . . . . . . . . . . . . 28
3.18 Decompiled bytecode of the interface declared in the aspect (ajc). . . . . 28
3.19 Variation in class extension declaration. . . . . . . . . . . . . . . . . . . . 29
3.20 Class extension inter-type declaration example. . . . . . . . . . . . . . . 29
xviii
LISTINGS xix
3.21 Variation in class interface implementation declaration. . . . . . . . . . . 29
3.22 Interface implementation inter-type declaration example. . . . . . . . . . 30
3.23 Inter-type method declaration example . . . . . . . . . . . . . . . . . . . 31
3.24 Declaration of inter-type method on BlankClass (ajc). . . . . . . . . . . . 31
3.25 Inter-type method implementation and dispatcher methods in the aspect
(ajc). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.26 Declaration of inter-type method on BlankClass (abc). . . . . . . . . . . 32
3.27 Inter-type method implementation in the aspect (abc). . . . . . . . . . . 32
3.28 Class with private field and method. . . . . . . . . . . . . . . . . . . . . 34
3.29 Accessor methods created by ajc in the target class. . . . . . . . . . . . . 34
3.30 Accessor methods created by abc. . . . . . . . . . . . . . . . . . . . . . . 35
3.31 after call advice example. . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.32 Method affected by after call advice (ajc). . . . . . . . . . . . . . . . . . 36
3.33 Implementation method for the after call advice (ajc). . . . . . . . . . . . 37
3.34 Method affected by after call advice (abc). . . . . . . . . . . . . . . . . . 37
3.35 Aspect with an after returning call advice. . . . . . . . . . . . . . . . . . 38
3.36 Method affected by an after returning advice (ajc). . . . . . . . . . . . . 38
3.37 Method affected by an after returning advice (abc). . . . . . . . . . . . . 38
3.38 Before execution example. . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.39 Method affected by a before execution advice (ajc). . . . . . . . . . . . . 39
3.40 Body of the before execution advice implementation method (abc). . . . 39
3.41 Method affected by a before execution advice (abc). . . . . . . . . . . . . 40
3.42 around execution example. . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.43 Method affected by around advice (ajc). . . . . . . . . . . . . . . . . . . 41
3.44 Unused methods created by around advice (ajc). . . . . . . . . . . . . . . 42
3.45 Method affected by around advice (abc). . . . . . . . . . . . . . . . . . . 42
3.46 Interface created by around advice (abc). . . . . . . . . . . . . . . . . . . 43
4.1 Core loop of inliners in AbstractInliner. . . . . . . . . . . . . . . . . . . . 48
4.2 Static Method Inliner. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
4.3 Instance Method Inliner. . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
4.4 Implementation of the unnecessary aspectOf() remover algorithm. . . . . 51
4.5 after returning call advice example. . . . . . . . . . . . . . . . . . . . . . 52
LISTINGS xx
4.6 Method affected by an after returning advice. . . . . . . . . . . . . . . . 52
4.7 Method affected by an after returning advice (optimized). . . . . . . . . . 53
4.8 Init Inliner. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
4.9 FieldInit Inliner. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
4.10 Initialized inter-type field declaration example. . . . . . . . . . . . . . . . 56
4.11 Decompiled bytecode of the class after initialized inter-type field insertion. 56
4.12 Inter-type field initialization methods in the aspect. . . . . . . . . . . . . 56
4.13 Optimized initialization of inter-type field declaration. . . . . . . . . . . . 57
4.14 Inter-type Method Inliner Implementation. . . . . . . . . . . . . . . . . . 60
4.15 Check for parameters equivalence. . . . . . . . . . . . . . . . . . . . . . . 61
4.16 Inter-type method declaration example. . . . . . . . . . . . . . . . . . . . 61
4.17 Declaration of inter-type method on BlankClass (abc). . . . . . . . . . . 62
4.18 Inter-type method implementation in the aspect (abc). . . . . . . . . . . 62
4.19 Optimized initialization of inter-type attribute declaration. . . . . . . . . 62
4.20 Implementation of the accessor inliner optimization. . . . . . . . . . . . . 65
4.21 Access to private members example. . . . . . . . . . . . . . . . . . . . . . 66
4.22 Decompiled bytecode of the class affected by advice with access to private
members. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.23 Decompiled bytecode of the class affected by advice with access to private
members (optimized). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.24 Optimizations scheduling. . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.1 Aspect for the photo feature adding a new command to the screen . . . . 76
5.2 Command in CaptureVideoScreen in the conditional compilation version
of MobileMedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5.3 Main menu screen singleton declaration in PhotoAndMusicAndVideoAspect 77
5.4 Main menu screen singleton declaration in PhotoAndMusicAspect . . . . 77
CHAPTER 1
INTRODUCTION
“Most human beings have an almost infinite capacity for taking things
for granted.”
—ALDOUS HUXLEY
The mobile application market is a rapidly growing segment of the software industry.
A company that wishes to enter this market must be aware of the particularities of
mobile development in order to succeed. In order to increase its market penetration and
chances of success, companies need to make their mobile applications available to a wide
variety of devices, which possess several distinct characteristics, resources, limitations
and development platforms.
These characteristics of the mobile application environment led to the adoption of
the Software Product Line [CN02] (SPL) framework, which can enable large scale reuse,
productivity increase and a reduction in development costs. A SPL can be defined as sets
of software systems that satisfy the needs of a particular market, share a common set
of characteristics, being, however, sufficiently distinct among each other, and developed
from a set of reusable artifacts.
The definition of a SPL is in line with mobile software development, where the mobile
application has a common set of assets, shared by all devices, and variabilities in these
assets that tailor the application for a particular device. The adaptation of the application
for different devices is called porting [ACV+05].
A key factor in the development of a SPL is the mechanism used for structuring
source code variations, an integral part of the porting process. Nowadays, the most
widely used technique for structuring code variation in SPLs for the Java ME mobile
platform is conditional compilation [CLG+06], also called preprocessing, which leads to
code tangling and scattering, low legibility and low modularity [Alv07, Jun08].
Despite its disadvantages, which affect development and maintenance, conditional
1
INTRODUCTION 2
compilation has one significant advantage over other techniques available, which is that
it does not add size overhead to the compiled binary of the product line’s instances.
Other techniques are being analyzed to replace or coexist with conditional compila-
tion. Among the most promising alternative techniques for structuring code variation in
Java ME SPLs is the use of Aspect-Oriented Programming [KLM+97, ANS+06], through
AspectJ [KHH+01], an extension to the Java language.
AOP is considered a more elegant [Alv07, Jun08] approach than conditional compi-
lation because it untangles the variation code from the base code that is common to all
products in the line, providing better modularity and legibility.
Unfortunately, because of the way AspectJ compilers were designed to generate the
bytecode of aspects and modified Java classes, using AspectJ instead of conditional com-
pilation has a major drawback: it adds size overhead to the bytecode generated, even
with the use of bytecode optimizers [Pro07].
In the mobile applications context, even small size overheads are sometimes pro-
hibitive, due to a great number of devices in the market having strict memory lim-
itations. Even though the tendency is that the devices evolve to have more mem-
ory, so will increase the applications complexity. Therefore reducing this overhead can
be a differential for creating richer, feature-filled and responsive applications. Recent
works [ACH+05b, Kuz04, Cor07] show that there is still room for AspectJ code genera-
tion optimization.
Thus, we hypothesize that if the points where AspectJ compilers are generating size
overhead are identified and the proper optimizations are applied, the use of AspectJ as
variation structuring mechanism could become a viable option for Java ME Software
Product Lines.
In order to validate our hypothesis, we analyzed the code generation of AspectJ com-
pilers and identified where the bytecode could be optimized to decrease the size overhead.
This analysis led to the development of four optimizations that were put to test with two
mobile application SPLs, where we managed to achieve a 100% decrease in overhead in
one SPL and a decrease of approximately 50% in the overhead of the other SPL.
Finally, we ran AspectJ benchmark programs compiled with our optimizations that
show that our optimizations do not decrease the performance of AspectJ programs.
1.1 SUMMARY OF GOALS 3
1.1 SUMMARY OF GOALS
With the objective of enhancing AspectJ code generation to make it viable as a code
variation structuring mechanism in Java ME Software Product Lines, we can list our
work’s individual goals needed to reach our objective:
� Identify bytecode generation overhead points in two AspectJ compilers;
� Implement optimizations that reduce this overhead;
� Elaborate on the correctness of the optimizations
� Evaluate the implemented optimizations to show how they reduce bytecode size
and do not decrease performance.
1.2 ORGANIZATION
This dissertation is organized as follows:
1. Chapter 2 reviews essential concepts used throughout this work: Software Prod-
uct Lines, Conditional Compilation and Aspect-Oriented Programming. It also
shows how Conditional Compilation and Aspect-Oriented Programming are used
to structure variations and describes the two AspectJ compilers used in this study.
2. Chapter 3 shows, in a quantitative manner, how much overhead AspectJ generates
in a mobile game SPL and explores the code generation of AspectJ constructs that
lead to this overhead.
3. Chapter 4 proposes optimizations to eliminate the overhead in the constructs an-
alyzed. We also discuss the implementation and correctness of the optimizations
and present examples of the application of each optimization.
4. Chapter 5 describes the evaluation of the optimizations developed when applied
to two SPLs, both having a purely preprocessed version and one having a hybrid
version (AspectJ coexisting with conditional compilation) while the other has a
pure AspectJ version. We also present performance benchmarks in this chapter.
1.2 ORGANIZATION 4
5. Chapter 6 summarizes the contributions of this research, discusses limitations, re-
lated and future work, and presents our conclusions.
CHAPTER 2
BACKGROUND
Quis custodiet ipsos custodes?
—JUVENAL
In this chapter the main concepts of this work are presented. First, we discuss Software
Product Lines in Section 2.1. In this context, we discuss commonalities and variabilities
in Section 2.1.1. In Section 2.2 we explain what is conditional compilation and how it
is used to structure code variation in Java ME Software Product Lines, and also present
its shortcomings and advantages. Then, in Section 2.3, we give a short introduction to
AspectJ, describing the language and compilers, and explain how it can fill the same
role as conditional compilation in structuring code variations in SPLs, also presentind its
shortcomings and advantages.
2.1 SOFTWARE PRODUCT LINES
Software Product Lines [CN02] is a framework of processes that focus on the development
of a family of products that share a common base of artifacts and target a specific market.
In a product Line there is a generic architecture common to all products in the line. This
architecture is adapted for the creation of a specific product, called an instance of the
product line. Each product is defined by a selection of features, which are attributes that
characterize the functionalities of each instance.
The SPL approach increases productivity [vdLSR07] by enabling the generation of
related software products from reusable assets. These assets are not restricted to source
code, as requirements, art, test cases, can all be reused and composed in different ways
to produce an instance of the product line. According to Pohl et al. [PBvdL05a], there
are some benefits that justify using the product line approach: reduction of development
costs, enhancement of quality and reduction of time-to-market, all desirable benefits for
mobile applications development.
5
2.2 CONDITIONAL COMPILATION 6
2.1.1 Commonalities and Variabilities
Commonalities are the basis of SPLs. They are what drives a company to use the SPL
approach and can be defined as the set of artifacts that are common to all products in a
software family. If there is not much commonality between products of a software family,
developing them using the SPL approach might not be beneficial. When there is a good
amount of commonality, the benefits of developing as a SPL can be reaped.
Variability is what makes each instance of a product line unique, it is what makes it
different from the other products. A product can vary by adding, removing or modifying
its possible features. Variations can manifest at different times, called binding times,
which are: compile-time, load-time and run-time. The decision of which of these ap-
proaches to use is influenced by several factors, among those we can cite the environment
where the product will execute, performance requirements, security requirements.
In this work, we focus on source code variabilities bound at compile time. There
are several mechanisms to structure this type of variability, the most common being
conditional compilation. More recently, AspectJ has been investigated as an alternative
to conditional compilation [ANS+06].
2.2 CONDITIONAL COMPILATION
Conditional compilation, or code preprocessing, is a technique that allows specific code
snippets to be included in a compilation only when specific parameters, typically defined
in the build specification, are true. Conditional compilation is commonly used in C and
C++ programs, but with the need to have such functionality in Java ME applications, it
has become the standard for structuring code variation at compile time in Java as well.
The example in Listing 2.1, extracted from the BestLap SPL, illustrates code varia-
tion selection based on the definition of tags. When a build specification has defined the
tags that satisfy the expression after the \#if markup, the code right after it is uncom-
mented for compilation. However, when the the expression is not satisfied, the code is
automatically commented.
This example shows that, depending on the API available on the device, the canvas
class responsible for drawing the game may extend or implement different classes and
interfaces. The reason being that not all devices have the MIDP2 GameCanvas class.
2.3 ASPECT-ORIENTED PROGRAMMING 7
1 //#i f d ev i c e g r aph i c s c anva s nok i au i
2 pub l i c c l a s s MainCanvas extends FullCanvas {3 //#e l i f dev i c e g raph i c s canvas midp2 | | dev i c e g r aph i c s c anva s s i emens
4 //# pub l i c c l a s s MainCanvas extends GameCanvas {5 //#e l i f s ku i d s e 1
6 //# pub l i c c l a s s MainCanvas extends Canvas implements CommandListener {7 //#e l s e
8 //# pub l i c c l a s s MainCanvas extends Canvas {9 //#end i f
Listing 2.1 Conditional Compilation example.
Nokia, for instance, provides its own implementation of the canvas class (FullCanvas),
that performs better than the default implementation of GameCanvas, which they also
provide. We can see that using conditional compilation tangles the base code with the
different codes of each variation, making it hard to maintain and understand.
Through the use of tags to represent product line features, developers structure code
variation among different devices in a way that sacrifices code legibility, quality and main-
tainability [SC92, KS94, PBvdL05b] for performance. However, conditional compilation
does not add any size overhead to the compiled bytecode, which is its major advantage
over other variation structuring mechanisms.
2.3 ASPECT-ORIENTED PROGRAMMING
Aspect Oriented Programming (AOP) allows the implementation of crosscutting con-
cerns in a modular way. The most widely used AOP language is AspectJ, which is an
aspect-oriented extension of Java. Aspects can define pointcuts, advices and inter-type
declarations. Through these constructs, most of the code variations implemented with
conditional compilation can be implemented using AspectJ.
There is a very important concept in AOP called quantification [FF00], which is
used throughout this work. AOP allows programmers to make quantified programmatic
assertions over programs. These programmatic assertions allow some behavior (e.g., a
constraint check) to modify the execution of a program.
The types of execution points over which these assertions can be made, are called join
points and the programmatic assertions are called advices. One individual programmatic
assertion, an advice, can affect more than one point in the program. This mechanism
2.3 ASPECT-ORIENTED PROGRAMMING 8
1 pub l i c aspect NokiaCanvasAspect {2 de c l a r e parents : com . meantime . j2me . MainCanvas extends FullCanvas ;
3 }
Listing 2.2 AspectJ structuring the Nokia canvas variation.
1 pub l i c aspect Midp2CanvasAspect {2 de c l a r e parents : MainCanvas extends GameCanvas ;
3 }
Listing 2.3 AspectJ structuring the MIDP2 canvas variation.
of applying the same behavior to more than one point in the program is the definition
of quantification, which is very useful to implement some types of crosscutting concerns
that have the same type of behavior added to several different points in a program.
Listings 2.2 and 2.3 illustrate the structuring of two of the variations present in List-
ing 2.1 with aspects. Each one of these simple aspects contain an inter-type declaration
that implements one of the variations in Listing 2.1, namely the one for using the Nokia
canvas API and the one for MIDP2 Canvas.
With these aspects, we are able to remove the preprocessed code that changed the
class hierarchy, untangling the variation code from the base code. Other conditional
compilations blocks of each of these features, spread throughout this or other classes,
can now be modularized in these aspects, thus solving the scattering problem. We now
provide a quick description of the main concepts of the AspectJ language.
2.3.1 Pointcuts
Pointcuts define a set of points in the execution flow of a program. These individual points
are called join points. Some of the join points that can be captured by pointcuts are:
method call and execution (the difference between call and execution is that call denotes
a join point before entering a method, and execution is right after entering the method),
constructor call and execution, field set, field get, among others. Advices use pointcuts
to specify the join points in the program where they wish to modify the behavior.
Pointcut designators are used for defining pointcuts. For instance, execution(public
void ClassWithMethods.affectedMethod(..)), in Listing 2.5, captures the execution
2.3 ASPECT-ORIENTED PROGRAMMING 9
of a public method called affectedMethod(), which takes any number of parameters,
and is defined in the class ClassWithMethods.
Pointcuts are the constructs that define the quantification of advices, the program-
matic assertions mentioned before. They are used in advice definitions to specify which,
and, as a consequence, how many points in the program the assertions, that is, the
advices, have influence over.
2.3.2 Advice
Advices specify code to be executed before, after or around (instead of) a captured
join point. The after advice has three forms: after returning executes the advice
code only after the join points executes successfully, and it can also expose the returned
value; after throwing is used to execute the advice only if the join point captured raises
a specific exception, and it can also expose the exception; the last form is the unqualified
after, which executes the advice whether the join point is executed successfully or not.
The around advice can execute code before and after the join point, and even make
the code in the join point run multiple times, or not at all, through the use of a proceed()
call. The proceed() call allows the execution of the captured join point. As such, the
join point can be completely overwritten if proceed() is not called. It can also alter the
values of the context exposed to the join point.
Listing 2.4 shows a class that is affected by the before execution advice in List-
ing 2.5. What this advice does is executing a call to setBoolean() right at the beginning
of the affected method. This behavior modification enables the removal of most, but not
all, of preprocessed variations in the beginning of methods.
2.3.3 Inter-type Declarations
Besides modifying the dynamic execution of the program, an aspect can also modify its
static structure. The mechanisms provided by inter-type declarations are the introduction
of new attributes or methods to existing classes or interfaces, and the modification of the
class hierarchy, indicating that a class extends some other class or implements one or
more interfaces.
We show in Listing 2.2 an example of an inter-type declaration which alters the class
2.3 ASPECT-ORIENTED PROGRAMMING 10
1 pub l i c c l a s s ClassWithMethods {2 pr i va t e boolean bool ;
3
4 pub l i c void af fectedMethod ( ) {5 }6
7 pub l i c void setBoolean ( boolean bool ) {8 t h i s . bool = bool ;
9 }10 }
Listing 2.4 Class affected by before execution.
1 pub l i c aspect BeforeExecut ion {2 be f o r e ( ClassWithMethods c t h i s ) :
3 execut ion ( pub l i c void ClassWithMethods . af fectedMethod ( . . ) ) && th i s ( c t h i s ) {4 c t h i s . setBoolean ( f a l s e ) ;
5 }6 }
Listing 2.5 Aspect with before execution advice.
hierarchy, making the class MainCanvas extend the class FullCanvas from the Nokia API
which is equivalent to the corresponding conditional compilation block in Listing 2.1.
2.3.4 Compilers
AspectJ compilers generate bytecode, from Java and AspectJ code, that can be executed
in the standard Java Virtual Machine [LY99]. AspectJ compilers transform the AspectJ-
specific constructs to pure Java in a process called weaving. For some time, the first
implementation of AspectJ, ajc, weaved at the source code level, that is, it modified the
affected Java classes source files. But then, it switched to weaving at the bytecode level,
compiling the classes first and then modifying their bytecode according to the AspectJ
constructs. The standard for most AspectJ compilers now is to weave at the bytecode or
some intermediate representation level.
2.3 ASPECT-ORIENTED PROGRAMMING 11
2.3.4.1 ajc
The ajc compiler is the official implementation of AspectJ. It is integrated with the Eclipse
development environment through the AspectJ Development Tools (AJDT) plugin, is an
extension of the Java Development Tools (JDT), that provides Java development facilities.
Being integrated with Eclipse, it provides the expected features for a compiler in an
Integrated Development Environment (IDE), such as incremental compilation, bytecode
instrumentation for debugging, among others. The weaving process of ajc is described in
[HH04].
2.3.4.2 abc
AspectBench Compiler (abc) is an academic compiler [ACH+05a] that implements the As-
pectJ language. It allows the extension of the AspectJ language with new constructs and
optimizations. It uses the Soot [ACH+04, VRHS+99, VRGH+00] optimization frame-
work for bytecode optimization and generation. The weaving process in abc does not
happen directly at bytecode level, but at an intermediate representation level with Jim-
ple [VRH98].
Jimple is intermediate representation of a Java program. It uses a form of 3-address
code [S.M97], which means each instruction can be described by a 4-tuple of the form
x = y op z. Jimple is also fully typed, that is, it is possible to know the type of each
expression or variable. The number of instructions in Soot, 15, is considerably smaller
than the one from pure bytecode, 200 instructions, while maintaining the same expres-
siveness. These characteristics make Jimple a suitable language for implementing analysis
and transformations in Java programs.
In the next chapter we present our overhead analysis with both AspectJ compilers,
ajc and abc.
CHAPTER 3
ANALYZING THE PROBLEM
“The Difficult is that which can be done immediately; the Impossible
that which takes a little longer.”
—GEORGE SANTAYANA
In order to evaluate the overhead added by AspectJ, we performend an inspection
process that consisted of two steps: size analysis and AspectJ constructs inspection. The
objective of the size analysis was to quantify how much overhead in bytecode size AspectJ
adds to BestLap, a Java ME game product line, in order to get an idea of how significant
the overhead is. The source code of all programs used in this work is available on the
internet1, however, the BestLap source code will not be released publicly because it is a
private property of Meantime Mobile Creations.
The individual constructs inspection was based on a list of constructs that were elicited
during the FLiP project [CBS+07], which, as case studies, created an AspectJ version
of two game product lines that were developed originally with conditional compilation:
BestLap2, the product line used in our size analysis, and Juggling3, both commercial
games. Their original conditional compilation version was refactored [FBB+99, Col05]
into a version that used aspects to structure variations. However, this other version also
has conditional compilation where AspectJ was not capable of replacing it due to lack of
expressive power to represent some of the more fine grained variations, such as adding a
new else if block to an existing if-else structure.
The original version of BestLap has approximately 20K Lines of Code (LOC) in 14
classes with conditional compilation, which accounts for the entire base and variations
code. The refactored version with AspectJ and conditional compilation has approximately
21.5 KLOC in 14 classes (15.5 KLOC) and 48 aspects (6 KLOC), with each instance of
1http://www.cin.ufpe.br/~fhcl/msc2http://www.meantime.com.br/claro/jogo_ayrtonsenna.html3http://www.meantime.com.br/pt/jogo_ronaldinho.html
12
3.1 SIZE ANALYSIS 13
the product line having, on average, 18 aspects. We shall henceforth refer to the version
of BestLap with only conditional compilation as the original version, while the one with
AspectJ and conditional compilation will be refered to as the hybrid version.
As discussed before in Section 2.3, AspectJ provides quantification mechanisms that
allow the same behavior to modify the execution of different join points in the program.
However, due to the nature of the variations encountered in these product lines, there
was no common behavior in conditional compilation code that altered more than one
join point in the same way. Therefore, there is a 1:1 ratio between each variation in
conditional compilation and the equivalent implementation of the same variation with
AspectJ. This means that no advice in the hybrid version had quantification, that is,
each advice only modified the behavior of exactly one specific join point.
Moreover, seeing that each advice is derived by refactoring from a conditional com-
pilation code, as well as any attributes that they access, which may also be variations,
no aspect in the hybrid version possesses state (attributes or methods not automatically
generated by the compiler), only accessing the state of Java classes. The statelessness of
the aspects and the lack of quantification in the advices was not a design decision by the
implementors of the aspects, they were inherent to the product lines analyzed.
To realize the size analysis we used two AspcetJ compilers: ajc and abc. The ajc
compiler is the industrial strength implementation of AspectJ, while abc is an academic
compiler that implements the AspectJ language. We used both compilers for the size
analysis and for the code inspection.
3.1 SIZE ANALYSIS
The first step to analyze AspectJ overhead is to quantify it. We carried on to perform a
comparison of the sizes produced the build process of both versions, original and hybrid,
of the BestLap SPL. Being the standard in industry, code obfuscation is used after the
compilation, using Proguard [Pro07].
Figure 3.1 illustrates how the build process of BestLap works. It takes as input a
build specification file, which describes what preprocessing tags to use, which resources
to copy, optimization parameters, etc. The tags are used in the first step, where the
source code is modified based on which tags were selected. This modified source code
3.1 SIZE ANALYSIS 14
is then compiled, optimized and obfuscated. The art and language resources are copied
in the next step, after which they are compressed and packaged with the final compiled
bytecode.
Figure 3.1 BestLap build process
Aiming to have a broad penetration in the market, each game is developed for several
families of devices. Each family consists of a group of devices from the same manufacturer
that have similar characteristics. When a build is tested and approved on a family’s
reference device it can be deployed in any of the family’s devices. BestLap was developed
for 15 families, comprised of dozens of devices.
We used version 1.6.8 of the ajc compiler, version 1.2.1 of the abc compiler and version
1.6.0 16 of the javac compiler for our analysis. The box plot in Figure 3.2 shows that the
difference among the three compilers with the original version is quite small. A box plot
is a graphical way to depict numerical data through five statistical number summaries:
sample minimum, lower quartile, median, upper quartile and largest observation.
The sample minimum is the end point of the line connected to the bottom of the
rectangle, the lower quartile is the lower side of the rectangle, the median is the line
between the bottom and top of the rectangle, the upper quartile is the top side of the
rectangle and the largest observation is the end point of the line connected to the top of
rectangle.
3.1 SIZE ANALYSIS 15
Build ID javac ajc abc
MOT1 71,608 71,694 70,952
MOT2 83,979 84,073 83,327
MOT3 71,625 71,717 70,964
S40 64,052 64,130 63,492
S40M2 71,719 71,796 71,032
S40M2V3 71,194 71,268 70,537
S60M1 84,218 84,309 83,625
S60M2 83,101 83,205 82,499
SAM1 65,419 65,510 64,792
SAM2 79,261 79,388 78,707
SE02 82,931 83,046 82,359
SE03 71,271 71,346 70,618
SE04 71,195 71,273 70,563
SIEM3 71,940 72,013 71,312
SIEM4 71,156 71,227 70,533
Arithmetic Mean 74,311 74,400 73,687
Difference in relation to javac 0% 0.119% -0.839%
Table 3.1 Comparison (in bytes) of the original version of the product line
The box plots we present in this work will also show the minimum and maximum
outliers, that is, the observations that appear to deviate markedly from other members
of the sample in which they occur. If the outlier marker in the box plot matches end
point of the sample minimum or maximum line, it means that there were no values that
deviated markedly from the others. However, if the outlier marker falls outside the end
point of the lines, they will also be the sample maximum or minimum, with the end point
of the lines being the maxmimum or minimum values that are not outliers.
We can see in this box plot that the outliers match the sample minimum and max-
imum, which means that there were no samples too far outside the values of the other
samples. It also shows that abc performed better than ajc and javac.
We chose to use the abc compiler as the baseline compiler for building the original
3.1 SIZE ANALYSIS 16
Figure 3.2 Box plot of the original version of the product line
version of the game, because it yields better results than javac, as we can see on Table 3.1,
where we have on each line the identification name of each family of devices BestLap was
developed for, along with the size, in bytes, of the original version compiled with javac,
with ajc and abc for the respective family. The smaller code generated by abc is due to
the fact that abc uses the Soot framework not only for bytecode generation, but also for
optimizations, most of which javac does not perform.
We use the arithmetic mean for expressing the average of all numerical data in this
work, which is either number of bytes or seconds. The arithmetic mean was found to be
the best (other options are geometric and harmonic means) for representing performance
expressed as time in a single number [Smi88], while the harmonic mean is considered the
best for performance expressed as a rate, which is not the case in any of the numbers in
this work.
Table 3.2 presents the size, in bytes, of each build of the original version, compiled
with abc, and the hybrid version compiled with ajc and with abc. In the hybrid version,
the difference between ajc and abc is, on average, of 791 less bytes on abc. However, the
difference between the pure java version and the aspects version, both compiled with abc,
is, on average, of 6,629 bytes. This difference is very significant in the mobile applications
context.
It is important to note that every build of the hybrid version, compiled with either
3.1 SIZE ANALYSIS 17
ajc or abc, is larger than the corresponding build of the original version. Also, every
hybrid build with abc is smaller than the corresponding hybrid build with ajc, though
both are always larger than the original version. Therefore, we conclude that there is
always overhead with AspectJ, regardless of the compiler. However, this overhead is
always smaller with abc than with ajc.
Build ID Original (abc) Hybrid (ajc) Hybrid (abc)
MOT1 70,952 79,548 78,276
MOT2 83,327 92,270 90,675
MOT3 70,964 79,731 78,431
S40 63,492 71.112 69,597
S40M2 71,032 78,734 77,471
S40M2V3 70,537 78,558 77,325
S60M1 83,625 92,372 90,826
S60M2 82,499 91,376 89,823
SAM1 64,792 71,024 70,171
SAM2 78,707 83,626 82,753
SE02 82,359 89,802 88,564
SE03 70,618 78,418 77,221
SE04 70,563 78,351 77,198
SIEM3 71,312 79,806 78,547
SIEM4 70,533 79,129 77,865
Arithmetic Mean 73,687 81,590 80,316
Average size increase
in relation to original
0% 10.73% 9.00%
Table 3.2 Comparison (in bytes) of the original version against the hybrid version
As can be seen on Table 3.2, the average size increase between the original version’s
size and the version with aspects compiled with abc is of 9.00%, while compiling with ajc
we have an average increase of 10.73%. With the box plot in Figure 3.3, we can visualize
the overhead that results from having aspects in the hybrid version, making it clear that
the hybrid version with either compiler is much larger than the original version, whilst
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 18
showing that abc performs slightly better than ajc.
Figure 3.3 Box plot of the original version and the hybrid version
In the context of Java ME Software Product Lines, where there are devices with very
tight constraints of jar size allowed, and given that the developers tend to use as much
of the space available, an increase of 9.00% may render the build impossible to install on
some devices due to its larger size. This is the case with devices in the S40 family, for
instance, which do not allow the installation of Java ME applications with a jar size larger
than 64KB, making the hybrid version compiled with either abc or ajc uninstallable on
these devices. In the following section, we investigate the reasons behind this increase in
build size.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION
We saw in the previous section that using AspectJ constructs as a variability structuring
mechanism leads to an increase in build size of the product line instances we evaluated.
Before we are able to develop optimizations to reduce this overhead, we must under-
stand how each individual AspectJ construct affects the bytecode and how this generates
overhead.
In order to accomplish these prerequisites, we used a few examples of each type of
AspectJ construct found in the product line evaluated in the previous secion. Although
not all AspectJ constructs were analyzed, we managed to cover all types of advices,
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 19
static pointcuts and inter-type declarations. AspectJ features not covered by our in-
spection were: the exception handler pointcut, dynamic (cflow and cflowbelow) and
adviceexecution pointcuts, declare soft, declare error, declare warning, and
AspectJ 5 features, such as annotations, autoboxing and unboxing parameter matching,
covariance, varargs and enumerated types.
Some of these constructs that were not analyzed do not modify the bytecode, such as
declare error and declare warning, which only make static verifications at compile
time to issue warnings or errors. They were not analyzed but can be used freely in any
context, including Java ME SPLs.
Other constructs are not supported in mobile devices, such as dynamic pointcuts, due
to the absence of the reflection API, and also AspectJ 5 features, since those depend on
Java 5 features, which are also not available in mobile devices. Since Java 5 constructs
are mostly syntatic sugar, any program developed with Java 5 and AspectJ 5 can be im-
plemented with the older version of the Java and AspectJ languages. Dynamic pointcuts,
however, can be a feature missed by developers in programs that depend on them, since
a pure Java implementation of the behavior of an advice that uses a dynamic pointcut
can be very complicated to implement.
Thus, we believe that our analysis covers the most important AspectJ features which
are used for structuring variations in product lines. For simplicity, for each AspectJ
construct example, we show a decompiled version of the bytecode, generated by both
the ajc and the abc compiler, because we believe that presenting pure bytecode only
complicates the understanding of the examples and does not facilitate to the presentation
of the reasons behind the overhead.
3.2.1 Aspect Declaration
Before we start analyzing inter-type declarations and advices it is important to see how
much overhead a single blank aspect generates. Listing 3.1 presents a simple blank aspect,
which has no attributes, methods, inter-type declarations or advices whatsoever. This
aspect, when compiled with ajc, generates the code in Listing 3.2.
We notice that the bytecode generated by ajc has two attributes, three methods and
one static block. The attribute ajc$perSingletonInstance represents the Singleton
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 20
1 pub l i c aspect BlankAspect {2 }
Listing 3.1 Blank Aspect.
1 import org . a s p e c t j . lang . NoAspectBoundException ;
2
3 pub l i c c l a s s BlankAspect{4
5 pr i va t e s t a t i c Throwable a j c$ i n i tFa i l u r eCau s e ;
6 pub l i c s t a t i c f i n a l BlankAspect a j c$pe rS i ng l e t on In s t an c e ;
7
8 s t a t i c {9 t ry {
10 a j c $po s tC l i n i t ( ) ;
11 } catch ( Throwable loca lThrowable ) {12 a j c$ i n i tFa i l u r eCau s e = loca lThrowable ;
13 }14 }15
16 pub l i c s t a t i c BlankAspect aspectOf ( ) {17 i f ( a j c$pe rS i ng l e t on In s t an c e == nu l l ) {18 throw new NoAspectBoundException ( ”BlankAspect” , a j c$ i n i tFa i l u r eCau s e ) ;
19 }20 r e turn a j c$pe rS i ng l e t on In s t an c e ;
21 }22
23 pub l i c s t a t i c boolean hasAspect ( ) {24 r e turn a j c$pe rS i ng l e t on In s t an c e != nu l l ;
25 }26
27 pr i va t e s t a t i c void a j c $po s tC l i n i t ( ) {28 a j c$pe rS i ng l e t on In s t an c e = new BlankAspect ( ) ;
29 }30 }
Listing 3.2 Code generated by ajc for a blank aspect.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 21
instance of the aspect, while the attribute ajc$initFailureCause is meant to store
the reason of a possible initialization failure. The static block is executed when the
aspect bytecode is loaded by the VM, calls the ajc$postClinit method, which initializes
the aspect’s singleton instance. The aspectOf method returns the aspect’s Singleton
instance, while the method hasAspect tells whether this aspect has a singleton instance
that was successfully initialized.
The same aspect compiled with abc generates the code in Listing 3.3. The code
generated by abc is semantically equivalent to the one generated by ajc, with only minor
naming changes. Although it seems that both compilers generate code of the same size,
in reality, ajc’s bytecode is larger, 1152 bytes, than abc’s, 743 bytes.
This difference is due to the fact that ajc adds several classfile attributes to the
bytecode it generates. Classfile attributes are simple data structures used to annotate
the bytecode with information that is not part of the class structure, such as which lines
in the source file a group of bytecode instructions refer to. Classfile attributes are also
used by ajc to annotate weaved classes with the weaver version, to annotate methods
that were created by the compiler, not the developer, among other uses. The decompiled
bytecode presented does not show the classfile attributes, since these are not present in
Java code.
3.2.2 Inter-type Field Declarations
Inter-type field declarations enables the developer to structure variations of field decla-
rations that were contained in conditional compilation blocks. Firstly, we analyze the
introduction of fields with inter-type declarations in both of its possible forms:
� [ Modifiers ] Type OnType.Id;
� [ Modifiers ] Type OnType.Id = Expression;
An inter-type field declaration differs from a simple Java field declaration by having a
target type, represented by OnType in the grammar above. Like a Java field declaration,
an inter-type field declaration can be unitialized or initialized, which affects how the
compiler will generate its code. Both forms were used in the product lines analyzed to
replace variations of regular field declarations structured with conditional compilation.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 22
1 import org . a s p e c t j . lang . NoAspectBoundException ;
2
3 pub l i c c l a s s BlankAspect {4 pub l i c s t a t i c f i n a l BlankAspect abc$perS ing l e ton Ins tance ;
5 pr i va t e s t a t i c Throwable abc$ i n i tFa i lu r eCause ;
6
7 pub l i c s t a t i c BlankAspect aspectOf ( ) throws NoAspectBoundException {8 BlankAspect loca lBlankAspect = abc$perS ing l e ton Ins tance ;
9 i f ( loca lBlankAspect != nu l l ) {10 r e turn loca lBlankAspect ;
11 }12 throw new NoAspectBoundException ( ”BlankAspect” , abc$ i n i tFa i lu r eCause ) ;
13 }14
15 pub l i c s t a t i c boolean hasAspect ( ) {16 r e turn abc$perS ing l e ton Ins tance != nu l l ;
17 }18
19 s t a t i c {20 t ry {21 abc$pos tC l i n i t ( ) ;
22 } catch ( Throwable loca lThrowable ) {23 abc$ i n i tFa i lu r eCause = loca lThrowable ;
24 }25 }26
27 pr i va t e s t a t i c void abc$pos tC l i n i t ( ) {28 abc$perS ing l e ton Ins tance = new BlankAspect ( ) ;
29 }30 }
Listing 3.3 Code generated by abc for a blank aspect.
3.2.2.1 Unitialized
The code in Listing 3.4 presents a blank class and an aspect that introduces a field on
that class using an unitialized inter-type field declaration. In Listing 3.5 we show the
decompiled bytecode of BlankClass when the class and aspect are compiled using ajc.
We can see that, despite the field inter-type declaration being unitialized on the aspect,
the ajc compiler added a call on the affected class’ constructor to what appears to be a
static initialization method on the aspect. Listing 3.6 shows the methods created by the
ajc compiler in the aspect, as a result of the field inter-type declaration. Upon inspection,
we see that the method called by the class’ constructor is empty, and that there are also
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 23
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c aspect Attr ibuteAspect {5 pub l i c i n t BlankClass . x ;
6 }
Listing 3.4 Unitialized inter-type field declaration example.
1 pub l i c c l a s s BlankClass {2 pub l i c i n t x ;
3
4 pub l i c BlankClass ( ) {5 Attr ibuteAspect . a j c$ i n t e rF i e l d In i t$Att r i bu t eAspec t$BlankC la s s$x ( t h i s ) ;
6 }7 }
Listing 3.5 Decompiled bytecode of the class after unitialized field insertion (ajc).
two other methods which are not called by any class. Those two methods are dispatchers
automatically generated by the compiler which would be used by the aspect for getting
and setting the value of the inter-type field it added to the class.
1 pub l i c s t a t i c void a j c$ i n t e rF i e l d In i t$Att r i bu t eAspec t$BlankC la s s$x (
2 BlankClass a j c $ t h i s ) {3 }4
5 pub l i c s t a t i c i n t a j c$ i n te rF ie ldGetDispatch$Attr ibuteAspect$BlankClas s$x (
6 BlankClass paramBlankClass ) {7 r e turn paramBlankClass . x ;
8 }9
10 pub l i c s t a t i c void a j c$ i n t e rF i e ldSe tDi spatch$Attr ibuteAspec t$BlankClas s$x (
11 BlankClass paramBlankClass , i n t paramInt ) {12 paramBlankClass . x = paramInt ;
13 }
Listing 3.6 Decompiled bytecode of the field initialization method and dispatchers (ajc)
On the other hand, the abc compiler only modifies BlankClass adding the field, as we
see in Listing 3.7. There were no additional methods created on the aspect, which has a
classfile identical to the one presented in section 3.2.1. Therefore, the abc compiler does
not require any optimization for an unitialized inter-type field declaration, seeing it adds
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 24
no overhead to the target class of the declaration.
1 pub l i c c l a s s BlankClass {2 pub l i c i n t x ;
3 }
Listing 3.7 Decompiled bytecode of the class after unitialized field insertion (abc).
3.2.2.2 Initialized
The code in Listing 3.8 presents a blank class and an aspect that introduces a field on
that class using an initialized inter-type field declaration.
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c aspect Attr ibuteAspect {5 pub l i c i n t BlankClass . x = 1 ;
6 }
Listing 3.8 Initialized inter-type field declaration example.
The classfile generated by ajc for BlankClass is identical to the one in Listing 3.5.
However, the classfile for the aspect differs on the method that was blank in Listing 3.6,
as we can see in Listing 3.9.
1
2 pub l i c s t a t i c void a j c$ i n t e rF i e l d In i t$Att r i bu t eAspec t$BlankC la s s$x (
3 BlankClass a j c $ t h i s ) {4 a j c$ i n t e rF i e ldSe tDi spatch$Attr ibuteAspec t$BlankClas s$x ( a j c $ t h i s , 1) ;
5 }
Listing 3.9 Decompiled bytecode of the field initialization method (ajc).
The initialization method calls the field set dispatcher, which is a method created
by the compiler for setting the value of the inter-type field, passing the value specified
in the inter-type field initialization expression as a parameter. The set dispatcher then
sets the initial value of the field. This process as a whole is unnecessary, given that the
field initialization could have been done in the class’ constructor, instead of having two
methods generated and called for the same purpose.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 25
However, during development time, having these dispatcher methods is what allows
the debuggers to work, given that these methods can be annotated with classfile attributes
to identify which lines in the aspect source file they refer to. This would not be possible
if the initialization was done in the target class, because the Java bytecode specification
does not allow the source code line classfile attribute to refer to a different source file
than the one that generated the current classfile.
The creation of methods in the aspect classfile to correspond to the AspectJ constructs
in order to provide these debugging facilities is useful not only in ajc, but also in abc.
However, while this overhead is useful at development time, it is unnecessary for the final
release of programs to the devices.
The same code compiled with abc now generates a call to a field initialization method
on BlankClass’ constructor, similar to how ajc does it, which can be seen in Listing 3.10.
Listing 3.11 shows the two methods involved in the field initialization. We can see that
one method is acting only as a placeholder for the expression used in the inter-type field
declaration. Unlike ajc, abc does not create dispatchers, accessing the field directly, but
this initialization process is unnecessary, given that the field could have been initialized
in the class where it resides.
1 pub l i c c l a s s BlankClass {2 pub l i c i n t x ;
3
4 pub l i c BlankClass ( ) {5 Attr ibuteAspect . f i e l d i n i t $ 2 2 ( t h i s ) ;
6 }7 }
Listing 3.10 Decompiled bytecode of the class after initialized field insertion (abc).
1 pub l i c s t a t i c void f i e l d i n i t $ 2 2 ( BlankClass paramBlankClass ) {2 paramBlankClass . x = in i t$x$14 ( paramBlankClass ) ;
3 }4
5 pub l i c s t a t i c i n t i n i t$x$14 ( BlankClass paramBlankClass ) {6 r e turn 1 ;
7 }
Listing 3.11 Inter-type field initialization methods (abc).
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 26
3.2.2.3 Constants
In Java, constants are declared as static final primitive type members of classes. They
are useful in Java ME programming because their value is known at compile time, which
enables each access occurrence of the constant to be replaced by its value, reducing byte-
code size since there are no field access instructions for accessing the constant. Variation
in the definition of constants is one of the most commonly found type of variation in the
product lines analyzed.
There is, in fact, no way to declare a constant with an AspectJ inter-type field dec-
laration. An AspectJ inter-type field declaration with the modifiers static final only
creates a static field in the target class. The example in Listing 3.12, where we try to
declare an inter-type constant, does not work out as expected. As we can see in List-
ings 3.13 and 3.14, both, ajc and abc, create a static field which is not final and has
the same value initialization process we presented earlier for initialized inter-type fields.
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c aspect ConstantAspect {5 pub l i c s t a t i c f i n a l i n t BlankClass . x = 1 ;
6 }
Listing 3.12 Trying to add a constant with a inter-type field declaration
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c i n t x ;
3
4 s t a t i c {5 Attr ibuteAspect . a j c$ i n t e rF i e ld In i t$ConstantAspec t$BlankCla s s$x ( ) ;
6 }7 }
Listing 3.13 Failed attempt of constant insertion (ajc)
An alternative manner of using AspectJ to declare constants in a inter-type declaration
manner was devised using an interface declaration to contain the constants that need to
be defined on a given class and use an interface implementation inter-type declaration to
make the target class implement the constants interface.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 27
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c i n t x ;
3
4 s t a t i c {5 ConstantAspect . f i e l d i n i t $ 2 0 ( ) ;
6 }7 }
Listing 3.14 Failed attempt of constant insertion (abc)
This approach is worth the hassle of creating one interface for the constants because a
great part of the variations of the product lines analyzed corresponded to the declaration
of constants with different values, and since we know that bytecode optimizers replace the
constants declared in the interfaces with their values on each occurrence, we can achieve
not adding any overhead with a constant declaration with AspectJ using this scheme.
The class in Listing 3.15 demonstrates a class with a method that access a constant
being defined with the combination of an interface and inter-type declaration, which are
displayed in Listing 3.16.
1 pub l i c c l a s s BlankClass {2
3 pub l i c i n t constant ( ) {4 r e turn CONSTANT;
5 }6 }
Listing 3.15 Class where a constant is being inserted
1 pub l i c aspect ConstantAspect {2 pub l i c i n t e r f a c e Constants {3 pub l i c s t a t i c f i n a l i n t CONSTANT = 1 ;
4 }5 de c l a r e parents : BlankClass implements Constants ;
6 }
Listing 3.16 Constant declaration through interface implementation inter-type declaration.
This code compiled with ajc does not add any fields to the class, having the method
that accesses the constant return the value of the constant, as we can see in Listing 3.17.
Using the abc compiler we obtain a decompiled bytecode identical to the one generated by
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 28
ajc. Therefore, this scheme that uses an interface inter-type declaration to add a constant
to a class is free of overhead, since the interface can be removed by an optimizer.
1 pub l i c i n t constant ( ) {2 r e turn 1 ;
3 }
Listing 3.17 Decompiled bytecode of constant() method (ajc).
1 pub l i c ab s t r a c t i n t e r f a c e ConstantAspect$Constants {2 pub l i c f i n a l s t a t i c i n t CONSTANT = 1
3 }
Listing 3.18 Decompiled bytecode of the interface declared in the aspect (ajc).
3.2.3 Class Extension Inter-type Declaration
AspectJ provides a construct that allows the developer to change the class hierarchy of
the program, making a class extend another. The syntax for doing so is as follows:
� declare parents: TypePattern extends Type;
The semantics of this construct is that any class that matches TypePattern will extend
the class specified in Type. This type of inter-type declaration is used in the product lines
analyzed to implement the variation in Listing 3.19. Some families of devices provide
the developers with an extended or different implementation of the MIDP Canvas API,
therefore, the developers used conditional compilation to select among each extension
declaration with the appropriate class.
Listing 3.20 illustrates an example of an aspect making one class extend another,
which the same mechanism used to implement the aforementioned variation in the hybrid
version of the product lines. Both compilers generate essentially identical code, having
the class BlankClass modified to extend BlankSuperClass with no overhead at all. Given
that there is no overhead associated with this construct, there is no need to optimize
either compiler for this construct.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 29
1 //#i f d ev i c e g r aph i c s c anva s nok i au i
2 pub l i c c l a s s MainCanvas extends FullCanvas {3 //#e l i f dev i c e g raph i c s canvas midp2 | | dev i c e g r aph i c s c anva s s i emens
4 //# pub l i c c l a s s MainCanvas extends GameCanvas {5 //#e l i f s ku i d s e 1
6 //# pub l i c c l a s s MainCanvas extends Canvas implements CommandListener {7 //#e l s e
8 //# pub l i c c l a s s MainCanvas extends Canvas {9 //#end i f
Listing 3.19 Variation in class extension declaration.
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c c l a s s BlankSuperc lass {5 }6
7 pub l i c aspect HierarchyChanger {8 de c l a r e parents : BlankClass extends BlankSuperc lass ;
9 }
Listing 3.20 Class extension inter-type declaration example.
3.2.4 Interface Implementation Inter-type Declaration
AspectJ provides a construct that allows the developer to make one or more classes
implement any number of interfaces. The syntax for achieving this is as follows:
� declare parents: TypePattern implements TypeList;
The semantics of this construct is that any class that matches TypePattern will
implement the interfaces specified in TypeList. This type of inter-type declaration is used
in the product lines analyzed to implement the variation in Listing 3.21. We can see that,
depending on which of the conditional compilation tags are selected, the SoundEffects
class may implement different combinations of interfaces.
Listing 3.22 illustrates an example where a class is changed to implement an interface
as specified by an aspect, which is the mechanism used in the product lines analyzed to
implement the aforementioned variation in the hybrid version. As with class extension,
the only change made to the bytecode is on the target class, making it implement the
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 30
1 //#i f dev i c e s ound ap i nok i a && dev i c e s ound p l ay b l o ck
2 pub l i c c l a s s SoundEf fects implements SoundListener {3 //#e l i f d ev i c e s ound ap i nok i a && dev i c e sound p lay th r ead
4 //# pub l i c c l a s s SoundEf fects implements SoundListener , Runnable {5 //#e l i f d ev i c e s ound p l ay b l o ck
6 //# pub l i c c l a s s SoundEf fects {7 //#e l i f d ev i c e sound p lay th r ead
8 //# pub l i c c l a s s SoundEf fects implements Runnable {9 //#end i f
Listing 3.21 Variation in class interface implementation declaration.
interface, with no overhead at all. Therefore, this inter-type declarion does not need to
be optimized in either compiler.
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c i n t e r f a c e B lank In te r f a c e {5 }6
7 pub l i c aspect HierarchyChanger {8 de c l a r e parents : BlankClass implements B lank In te r f a c e ;
9 }
Listing 3.22 Interface implementation inter-type declaration example.
3.2.5 Inter-type Method Declaration
Similar to inter-type field declaration, AspectJ provides a construct that allows a method,
abstract or concrete, to be added to a target class. There were variations identified in
the product lines analyzed that consisted of the definition of methods in conditional com-
pilation blocks, which is structured, in AspectJ, with an inter-type method declaration.
The syntax for inter-type method declarations is as follows:
� [ Modifiers ] Type OnType . Id(Formals) [ ThrowsClause ] { Body }
� abstract [ Modifiers ] Type OnType . Id(Formals) [ ThrowsClause ];
In Listing 3.23 we have ITMethodAspect adding a method called x, which returns an
int, to BlankClass. Using ajc to compile this code we obtain the code in Listing 3.24.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 31
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {3 new BlankClass ( ) . x ( ) ;
4 }5 }6
7 pub l i c aspect ITMethodAspect {8 pub l i c i n t BlankClass . x ( ) {9 r e turn 0 ;
10 }11 }
Listing 3.23 Inter-type method declaration example
We can see that the method x on BlankClass only redirects to a static method in the
aspect class, which is shown in Listing 3.25. We can see that one of the methods is a
placeholder for the content of the inter-type method, and that the other is a dispatcher,
which is used whenever there’s a call for the method x. So, with ajc we have no direct
calls to the inter-type method, instead we have calls to the dispatcher, which we can see
in line 3 in the main method in Listing 3.24.
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {3 ITMethodAspect . ajc$ interMethodDispatch1$ITMethodAspect$BlankClass$x (
4 new BlankClass ( ) ) ;
5 }6
7 pub l i c i n t x ( ) {8 r e turn ITMethodAspect . ajc$ interMethod$ITMethodAspect$BlankClass$x (
9 t h i s ) ;
10 }11 }
Listing 3.24 Declaration of inter-type method on BlankClass (ajc).
Like initialized inter-type field declaration, seen in Section 3.2.2.2, the justification for
the creation of these methods in the aspect classfile is that they can be annotated with
the LineNumber classfile structure to enable debuggers to correctly show, in an Integrated
Development Environment (IDE), which line in the original source code of the aspect the
current execution stack is pointing to.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 32
1 pub l i c s t a t i c i n t ajc$ interMethod$ITMethodAspect$BlankClass$x (
2 BlankClass a j c $ t h i s ) {3 r e turn 0 ;
4 }5
6 pub l i c s t a t i c i n t ajc$ interMethodDispatch1$ITMethodAspect$BlankClass$x (
7 BlankClass a j c $ t h i s ) {8 r e turn a j c $ t h i s . x ( ) ;
9 }
Listing 3.25 Inter-type method implementation and dispatcher methods in the aspect (ajc).
With abc, we notice that the same pattern of creating a method in the aspect class
with the body of the inter-type method and having it being called at the target class’
method. However, abc does not create any dispatchers, having the call to the aspect
method on line 7 of Listing 3.26 be a direct call to the method with the inter-type
method’s body, not to a dispatcher, as we can see in Listing 3.27. As it is, abc generates
less overhead for method inter-type declarations than ajc.
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] paramArrayOfString ) {3 new BlankClass ( ) . x ( ) ;
4 }5
6 pub l i c i n t x ( ) {7 r e turn ITMethodAspect . x ( t h i s ) ;
8 }9 }
Listing 3.26 Declaration of inter-type method on BlankClass (abc).
1 pub l i c s t a t i c i n t x ( BlankClass paramBlankClass ) {2 r e turn 0 ;
3 }
Listing 3.27 Inter-type method implementation in the aspect (abc).
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 33
3.2.6 Advices
Advices are AspectJ constructs that enable the modification of the execution behavior
before, after or around one or more points in the program, which are called join points. In
order to specify which points should be affected by the advices, AspectJ uses expressions
called pointcuts. Variations inside the body of methods were encountered in conditional
compilation blocks in the product lines analyzed. In the hybrid version, advices were
used to structure these variations, when a suitable pointcut was available. When this
was not the case, the variations were left in conditional compilation. However, in most
cases, the variations could be successfully structured using advices.
The syntax for declaring advices is presented in grammar below:
� [ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body }
where AdviceSpec is one of the following:
� before( Formals )
� after( Formals ) returning [ ( Formal ) ]
� after( Formals ) throwing [ ( Formal ) ]
� after( Formals )
� Type around( Formals )
Our analysis identified that the join point captured does not influence how the advice
is applied. For instance, an after call advice and an after set advice which have
the same advice body will modify the affected join point in the same way. When using
pointcuts which capture the context of the join point, such as this() and target(), the
only difference they make is the addition of a new parameter when the compiler creates
advice implementation methods. Therefore, we will refrain from presenting an example
of each type of advice with each type of pointcut and instead will present one example
for each type advice, making one exception with the after advice, which requires two
examples.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 34
3.2.6.1 Access to private fields
Before we show the advices examples, we need to show how AspectJ handles access to
private fields within advice or inter-type method, which is permitted when the aspect is
qualified as privileged. Some variations, in conditional compilation, accessed private
members of the Java classes, therefore some aspects in the hybrid version had to be
privileged, in order to provide access to these private members.
Whenever an advice accesses a private field or method of an object, through context
exposed by the this() or target() pointcuts, for instance, there is an overhead associ-
ated with the way AspectJ makes them visible to the advice. Being private, there is no
way to access them directly, therefore, the compiler creates public accessor methods for
the advice to use.
1 pub l i c c l a s s ClassWithMethods {2 pr i va t e i n t x ;
3
4 pr i va t e void someMethod ( ) {5 }6 /*
7 * Other methods omitted
8 */
9 }
Listing 3.28 Class with private field and method.
If the class in Listing 3.28 has its private field and method accessed by an advice or
inter-type method, the ajc compiler creates the methods, presented in Listing 3.29, in the
target class, in order to provide access to the private members. The first two methods
are the accessors for the private field, one for getting and another for setting its value,
and the last is the method accessor, so that the advice can access the private method
through the public accessor.
The abc compiler also creates accessors, as we can see in Listing 3.30. However, there
is a difference between ajc and abc in the case of private field, while ajc creates static
methods which receive an instance of an object of the class, abc creates instance methods
in the class, which reduces size of the bytecode, given that there is no need for passing
the object as a parameter to the method.
We can see that accessing private members in an advice body leads to considerable
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 35
1 pub l i c s t a t i c i n t ajc$privFie ldGet$Aspect$ClassWithMethods$x (
2 ClassWithMethods paramClassWithMethods ) {3 r e turn paramClassWithMethods . x ;
4 }5
6 pub l i c s t a t i c ajc$privFie ldSet$Aspect$ClassWithMethods$x (
7 ClassWithMethods paramClassWithMethods , i n t paramInt ) {8 paramClassWithMethods . x = paramInt ;
9 }10
11 pub l i c void ajc$privMethod$Aspect$ClassWithMethods$someMethod ( ) {12 someMethod ( ) ;
13 }
Listing 3.29 Accessor methods created by ajc in the target class.
1 pub l i c i n t ge t$acce s so r$x$17 ( ) {2 r e turn x ;
3 }4
5 pub l i c i n t s e t$acc e s so r$x$18 ( i n t paramInt ) {6 t h i s . x = paramInt ;
7 r e turn paramInt ;
8 }9
10 pub l i c void accessor$someMethod$19 ( ) {11 someMethod ( ) ;
12 }
Listing 3.30 Accessor methods created by abc.
overhead, requiring the creation of two accessor methods for each private field accessed
and one accessor method for each private method accessed. Therefore, access to private
fields in an advice or inter-type method is subject to optimization.
3.2.6.2 After
The after advice is used to modify the behavior of the program after a specific join
point. In Listing 3.31 we are using an after call advice on a class with three methods:
affectedMethod, callee and someMethod. In this example, we wish to insert a call to
someMethod after the call to callee inside affectedMethod.
This advice binds the current object in the execution context to a variable called
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 36
1 pub l i c c l a s s ClassWithMethods {2 pub l i c void af fectedMethod ( ) {3 t h i s . c a l l e e ( ) ;
4 }5
6 pub l i c void c a l l e e ( ) {7 }8
9 pub l i c void someMethod ( ) {10 }11 }12
13 pub l i c aspect A f t e rCa l l {14 a f t e r ( ClassWithMethods c t h i s ) :
15 c a l l ( pub l i c void ClassWithMethods . c a l l e e ( ) )
16 && th i s ( c t h i s )
17 && withincode ( pub l i c void ClassWithMethods . af fectedMethod ( ) ) {18 c t h i s . someMethod ( ) ;
19 }20 }
Listing 3.31 after call advice example.
cthis, which is used in the advice body. The pointcut specifies the exact join point
where we wish modify the behavior. The call pointcut specifies which method call join
point we wish to capture and the withincode pointcut specifies inside which method the
call must be located.
Listing 3.32 shows how ajc modifies the affected method to add the behavior specified
by the advice. We can see that a try-catch block was put around the call of the method
we captured with the pointcut, and also that a call to the advice method is made inside
the catch block and outside the catch block. This happens because of the semantics of
the unqualified after advice, which requires that the advice body executes whether the
join point executes with success or not.
This is a considerable overhead at the advice application site, with the insertion of a
try-catch block and two calls to the advice implementation method, which has its body
shown in Listing 3.33. However, if the after advice was qualified as returning, the
overhead would be greatly decreased, seeing that its semantics states that the advice
body should only be executed if the join point is executed with success.
This example compiled with abc presents the same behavior of creating a try-catch
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 37
1 pub l i c void af fectedMethod ( ) {2 t ry {3 c a l l e e ( ) ;
4 } catch ( Throwable loca lThrowable ) {5 Afte rCa l l . aspectOf ( ) . a j c$a f t e r$Afte rCa l l$1$be448d7e ( t h i s ) ;
6 throw loca lThrowable ;
7 }8 Afte rCa l l . aspectOf ( ) . a j c$a f t e r$Afte rCa l l$1$be448d7e ( t h i s ) ;
9 }
Listing 3.32 Method affected by after call advice (ajc).
1 pub l i c void a j c$a f t e r$Afte rCa l l$1$be448d7e ( ClassWithMethods c t h i s ) {2 c t h i s . someMethod ( ) ;
3 }
Listing 3.33 Implementation method for the after call advice (ajc).
block, as we can see in Listing 3.34. However, abc does not create a method with the
advice body in the aspect’s class, instead, it puts the advice body at the application site.
Given that the context necessary for the advice is available at the join point captured by
its pointcut, no overhead is associated with the use of the this() pointcut.
On the other hand, abc does add some overhead to the affected method, creating a
local variable, an if check to compare if that local variable is null (though we believe this
is an unnecessary process) and it also leaves calls to the aspect’s static singleton getter,
not using it for anything.
In Listing 3.35 we present an optimized version of the advice using the returning
qualifier to specify that the advice should only be executed when the join point executes
successfully. In Listing 3.36 we show how the ajc compiler modifies the affected method
using this new advice. We can see that the only modification made is the call to the
aspect’s instance getter and the advice implementation method, which is considerably
less overhead than the example we have shown previously.
In Listing 3.37 we can see that abc presents the same enhancement, not having a
try-catch block. We can also see that there is a call to the aspect’s instance getter.
However, the instance is not used to call an advice implementation method. In fact, the
advice body is located right below the aspectOf call, which makes the call to the aspect’s
instance getter completely unnecessary in this scenario.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 38
1 pub l i c void af fectedMethod ( ) {2 Object l o c a lOb j e c t = nu l l ;
3 t ry {4 c a l l e e ( ) ;
5 } catch ( Throwable loca lThrowable ) {6 i f ( l o c a lOb j e c t == nu l l ) {7 Afte rCa l l . aspectOf ( ) ;
8 someMethod ( ) ;
9 throw loca lThrowable ;
10 }11 }12 Afte rCa l l . aspectOf ( ) ;
13 someMethod ( ) ;
14 }
Listing 3.34 Method affected by after call advice (abc).
1 pub l i c aspect A f t e rCa l l {2 a f t e r ( ClassWithMethods c t h i s ) r e tu rn ing :
3 c a l l ( pub l i c void ClassWithMethods . c a l l e e ( ) )
4 && th i s ( c t h i s ) {5 c t h i s . someMethod ( ) ;
6 }7 }
Listing 3.35 Aspect with an after returning call advice.
1 pub l i c void af fectedMethod ( ) {2 c a l l e e ( ) ;
3 Afte rCa l l . aspectOf ( ) . a j c$a f t e rReturn ing$Afte rCa l l$1$be448d7e ( t h i s ) ;
4 }
Listing 3.36 Method affected by an after returning advice (ajc).
1 pub l i c void af fectedMethod ( ) {2 c a l l e e ( ) ;
3 Afte rCa l l . aspectOf ( ) ;
4 someMethod ( ) ;
5 }
Listing 3.37 Method affected by an after returning advice (abc).
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 39
3.2.6.3 Before
The before advice is used to modify the behavior of the program before a specific join
point. In Listing 3.38 we show an example of a before execution advice, which makes
the method setBoolean be called before the execution of the method affectedMethod.
1 pub l i c c l a s s ClassWithMethods {2
3 pr i va t e boolean bool ;
4
5 pub l i c void af fectedMethod ( ) {6 System . out . p r i n t l n ( ) ;
7 }8
9 pub l i c void setBoolean ( boolean bool ) {10 t h i s . bool = bool ;
11 }12 }13
14 pub l i c aspect BeforeExecut ion {15 be f o r e ( ClassWithMethods c t h i s ) :
16 execut ion ( pub l i c void ClassWithMethods . af fectedMethod ( . . ) )
17 && th i s ( c t h i s ) {18 c t h i s . setBoolean ( f a l s e ) ;
19 }20 }
Listing 3.38 Before execution example.
Compiling this code with ajc, we see in Listing 3.39 how it modifies the affected
method. Much like the after returning advice, the only change was a call to the
aspect’s singleton getter and a call to the advice implementation method, both inserted
at the join point specified by the advice, the beginning of the method. In Listing 3.40 we
can see that the advice implementation method contains the body of the advice.
1 pub l i c void af fectedMethod ( ) {2 BeforeExecut ion . aspectOf ( ) . a jc$before$BeforeExecut ion$1$c60adbbd ( t h i s ) ;
3 System . out . p r i n t l n ( ) ;
4 }
Listing 3.39 Method affected by a before execution advice (ajc).
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 40
1 pub l i c void ajc$before$BeforeExecut ion$1$c60adbbd ( ClassWithMethods c t h i s ) {2 c t h i s . setBoolean ( f a l s e ) ;
3 }
Listing 3.40 Body of the before execution advice implementation method (abc).
When we compile the same code with abc we obtain the code presented in Listing
3.41. As we can see, just like the after advice, it still leaves an unnecessary call to the
aspect’s singleton getter, and inlines the advice body to the application site.
1 pub l i c void af fectedMethod ( ) {2 BeforeExecut ion . aspectOf ( ) ;
3 setBoolean ( f a l s e ) ;
4 System . out . p r i n t l n ( ) ;
5 }
Listing 3.41 Method affected by a before execution advice (abc).
3.2.6.4 Around
The around advice is used to modify the behavior at the captured join point, making
it not execute, execute more than once, add conditions that must be fulfilled for it to
execute, among other uses. In Listing 3.42 we show an example of an around advice,
based in one found in the hybrid version, that modifies the behavior of a method that
compares two integer values. Originally, it made a simple comparison and returned true
if the integers had the same value, while the around advice modifies it to also return true
if one of the values is the negative of the other.
When compiling this example with ajc we obtain the code in Listing 3.43. We can
see that two methods were created as a result of the around advice, a placeholder for the
original body of the compare method, and a method for the advice body. The original
compare method was modified to only pass its arguments to the advice implementation
method. This simple around advice generated a lot of overhead with unnecessary aspect
instance getter calls, creation of new methods and a lot of parameter passing.
Besides that, it also created two unused methods in the aspect, as we can see in List-
ing 3.44. These two methods are not referenced anywhere in the generated code, meaning
that they could simply be removed without altering the execution of the program.
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 41
1 pub l i c c l a s s ClassWithMethods {2 pub l i c boolean compare ( i n t key1 , i n t key2 ) {3 r e turn key1 == key2 ;
4 }5 }6
7 pub l i c aspect AroundExecution {8 boolean around ( i n t key1 , i n t key2 ) :
9 execut ion ( pub l i c boolean compare ( int , i n t ) )
10 && args ( key1 , key2 ) {11 boolean temp = proceed ( key1 , key2 ) ;
12 r e turn temp | | key1 == −key2 ;
13 }14 }
Listing 3.42 around execution example.
1 pub l i c boolean compare ( i n t key1 , i n t key2 ) {2 i n t i = key1 ;
3 i n t j = key2 ;
4 r e turn compare aroundBody1$advice ( th i s , i , j ,
5 AroundExecution . aspectOf ( ) , i , j , nu l l ) ;
6 }7
8 pr i va t e s t a t i c f i n a l boolean compare aroundBody0 ( ClassWithMethods a j c$ t h i s ,
9 i n t key1 , i n t key2 ) {10 r e turn key1 == key2 ;
11 }12
13 pr i va t e s t a t i c f i n a l boolean compare aroundBody1$advice ( ClassWithMethods a j c$ t h i s ,
14 i n t key1 , i n t key2 , AroundExecution a j c$aspec t In s tance , i n t key1 , i n t key2 ,
15 AroundClosure a jc$aroundClosure ) {16 AroundClosure loca lAroundClosure = ajc$aroundClosure ;
17 i n t i = key2 ;
18 i n t j = key1 ;
19 boolean temp = compare aroundBody0 ( a j c$ t h i s , j , i ) ;
20 r e turn ( temp) | | ( key1 == −key2 ) ;21 }
Listing 3.43 Method affected by around advice (ajc).
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 42
1 pub l i c boolean ajc$around$AroundExecution$1$20a3e19e ( i n t key1 ,
2 i n t key2 , AroundClosure a jc$aroundClosure ) {3 boolean temp = ajc$around$AroundExecution$1$20a3e19eproceed (
4 key1 , key2 , a jc$aroundClosure ) ;
5 r e turn ( temp) | | ( key1 == −key2 ) ;6 }7
8 s t a t i c boolean ajc$around$AroundExecution$1$20a3e19eproceed ( i n t th i s ,
9 i n t paramInt1 , AroundClosure paramAroundClosure ) throws Throwable {10 r e turn Convers ions . booleanValue ( paramAroundClosure . run (
11 new Object [ ] {Convers ions . in tObjec t ( t h i s ) , Convers ions . in tObjec t ( paramInt1 ) }) ) ;12 }
Listing 3.44 Unused methods created by around advice (ajc).
While we saw that ajc generates a considerable amount of overhead, abc, on the other
hand, generates a much more compact code, as we can see in Listing 3.45. The decompiled
code is not properly a compilable java class because it uses internal bytecode instructions
that can’t be used in regular Java classes, such as assigning an integer to this, and using
0 and 1 as false and true. Nevertheless, it is a much simpler and compact code that
implements the around advice. Lines 4 to 8 represent the first line of the around advice,
while lines 10 to 15 represent the second line of the around advice.
1 pub l i c boolean compare ( i n t paramInt1 , i n t paramInt2 ) {2 AroundExecution . aspectOf ( ) ;
3
4 i f ( paramInt1 == paramInt2 ) {5 t h i s = 1 ;
6 } e l s e {7 t h i s = 0 ;
8 }9
10 i f ( ( t h i s != 0) | | ( paramInt1 == −paramInt2 ) ) {11 paramInt2 = 1 ;
12 } e l s e {13 paramInt2 = 0 ;
14 }15 r e turn paramInt2 ;
16 }
Listing 3.45 Method affected by around advice (abc).
Besides the Java class and aspect classfiles, one more classfile was created and is not
3.2 ASPECTJ CONSTRUCTIONS INSPECTION 43
referenced by the aspect, nor the Java class. In Listing 3.46 we present the decompiled
bytecode of the interface. This is probably a code that was used for advice generation
when it used closures, but now it is just a simple overhead that can be removed by
bytecode optimizers, since there is no reference to it. The around advice, on abc does
not need any particular optimization, besides the one also identified in the after and
before advices, which is the removal of the unnecessary aspectOf() call.
1 pub l i c i n t e r f a c e abc$proceed$AroundExecution$around$9 {2
3 pub l i c ab s t r a c t boolean abc$proceed$AroundExecution$around$0 ( i n t paramInt1 ,
4 i n t paramInt2 , i n t paramInt3 , i n t paramInt4 , i n t paramInt5 , i n t paramInt6 ) ;
5 }
Listing 3.46 Interface created by around advice (abc).
In this chapter, we saw why using AspectJ increases the bytecode size of the builds of
the product line we analyzed in Section 3.1. This increase, with ajc and abc, is partly due
to the need to provide debugging facilities to IDEs, which creates a lot of indirection that
results in larger bytecode and is also expected to decrease the execution time performance.
The knowledge acquired in this investigation is used to devise optimizations to minimize
this overhead, which we discuss in the next chapter.
CHAPTER 4
OPTIMIZATIONS
“Political language is designed to make lies sound truthful and murder
respectable, and to give an appearance of solidity to pure wind.”
—GEORGE ORWELL
In the previous chapter we saw that the abc compiler was found to be the one gener-
ating less overhead when used to build the hybrid version of the product line evaluated
in the size analysis. The code inspection of the AspectJ constructs showed that some
constructs do not generate any overhead, while others can add a considerable overhead.
Based on the gathered data, we developed four optimizations for the abc compiler.
All optimizations were developed using the Soot framework, which is also used by abc,
and are executed on the classfiles generated by the abc compiler. They manipulate an
intermediate representation called Jimple, that greatly simplifies analyzing the bytecode,
since it is a 3-address code representation with much less instructions than bytecode,
while having the same expressive power. During the optimization process run by Soot,
after the optimizations have modified the Jimple code, it is transformed to bytecode at
a later stage. We use abc’s naming convention for its generated methods to identify
whether a method is a byproduct of having an inter-type method declaration, an advice
or an inter-type field declaration.
A basic assumption considered by our optimizations is that the ProGuard [Pro07]
bytecode optimizer will be executed after our optimizations have modified the bytecode.
Using ProGuard was mandatory for the commercial product lines we analyzed, so we
simply insert our optimizations one step before the execution of ProGuard’s bytecode
optimization and obfuscation, during the build process, as can be seen in Figure 4.1.
The importance of assuming that ProGuard is used is that our optimizations do not
have to worry about removing unreferenced methods and classes that were previously
being used before our optimizations took effect, which simplified their development.
44
OPTIMIZATIONS 45
Figure 4.1 Modified BestLap build process
Given this premise and its reasoning, the fundamental motivation behind our proposed
optimizations is that it is possible to remove the overhead generated by the compilers for
the ApectJ constructs analyzed in this work if the proper modifications to the bytecode
of the classes modified by aspects are made. The way to achieve this is simple: instead
of using the dispatchers, accessors and placeholder methods created by the compiler, we
have their calls replaced by the code they execute, a process called inlining.
Achieving this means that we effectively remove references to the aspect’s classfiles,
enabling their removal from the final build by ProGuard, thus eliminating the overhead
generated by the aspects. However, we use abc with the options to force advice inlining,
which yields an overhead reduction only in AspectJ programs that present little to no
quantification, usually the case with Software Product Lines. The inlining of advices is
what enables the application of some of our optimizations. If the program presents high
quantification, it is possible that this inlining combined with our optimizations, some of
which would not be applied, will increase the final build size.
The BestLap SPL analyzed in Chapter 3 had no quantification, therefore it is expected
that the overhead can be completely eliminated after applying the proposed optimiza-
tions. In the following sections we disccuss the small framework developed for inlining
4.1 INLINING FRAMEWORK 46
optimizations, how each optimization works, their preconditions and why they remove
the overhead associated with the AspectJ constructs they modify.
4.1 INLINING FRAMEWORK
We developed a set of classes that provide the basic functionality for optimizations that
inline method calls. This helped the development of our optimizations, given that three
of them involve inlining and using a framework minimizes the occurence of errors due to
better structuring of the common functionalities used by the optimizations. Algorithm 1
describes the functioning of the generic analysis. Each inliner goes through every state-
ment in each method of all classes in the system, identifies which of them are method
calls and tests for a condition, defined by each specific optimization, that must be true
for the inlining of the call to take place.
Algorithm 1: Generic Inliner Algorithm.
Input: Classes and aspects compiled by abc
Output: Classes and aspects optimized
1 foreach c in the set of classes do
2 foreach method m in class c do
3 foreach statement s in method m do
4 if s contains a method call then
5 mc ←− method call in s;
6 if mc matches a condition then
7 inline mc
8 end
9 end
10 end
11 end
12 end
The class AbstractInliner, with its core methods shown in Listing 4.1 implements
the main loop of the algorithm. Lines 1 and 2 of the algorithm are implemented by
the method internalTransform, while the method analyzeBody corresponds to line 3.
4.2 UNNECESSARY ASPECTOF() REMOVER 47
What differs among our optimizations is the analysis done on each individual statement,
which is realized by the abstract method analyzeStatement.
Listing 4.1 also shows, in line 43, a method of particular importance in our frame-
work, the isSafeToInline method. This method is used in every inlining optimiza-
tion and returns true when it is safe to inline a call at a given site. It uses Soot’s
InlineSafetyManager, a class that provides a method, ensureInlinability, that per-
forms the safety checks for us. Using this class from Soot saved us the trouble of de-
veloping some preconditions of our optimizations, because ensureInlinability already
checks them for us.
We simplify the analysis with the implementation of two classes, StaticInliner
and VirtualInliner, that override the method analyzeStatement, implementing lines
4 and 5 of the algorithm. The former checks if a method being called is static, while
the latter checks if it is an instance method. Listing 4.2 shows the implementation of
StaticInliner and Listing 4.3 shows the implementation of VirtualInliner. Both
classes check whether the method is being called by itself, in the form call() or if the
method is returning a value that is assigned to a variable, in the form x = call().
Each optimization implements their analysis of the individual method call by imple-
menting the method shouldBeInlined, which is called inside the tryToInline method,
seen in Listing 4.1. It returns true if the body of the method being called should be
inlined, and false if it should be left as is. This process corresponds to lines 6 and 7
of the algorithm. Our optimizations that use inlining extend either StaticInliner or
VirtualInliner, overriding the shouldBeInlined method, resulting in a very compact
and concise implementation of the optimization.
4.2 UNNECESSARY ASPECTOF() REMOVER
As we saw in Sections 3.2.6.2, 3.2.6.3 and 3.2.6.4, when we compile aspects with
advices using the abc compiler using the compiler options -around-force-inlining
-before-after-force-inlining, it inlines the body of advices, unlike ajc, which al-
ways creates methods in the aspect that contain the body of each advice. The fact that
abc inlines advices saves us the trouble of performing this task. However, we noticed
that, while the advice body is inlined, a call to the aspect’s singleton getter is left in the
4.2 UNNECESSARY ASPECTOF() REMOVER 48
1 protec ted void inte rna lTrans form ( St r ing phaseName , Map opt ions ) {2 f o r ( SootClass c : Scene . v ( ) . g e tApp l i c a t i onC la s s e s ( ) ) {3 f o r ( SootMethod m : c . getMethods ( ) ) {4 i f (m. i sConcre t e ( ) ) {5 i f ( !m. hasActiveBody ( ) ) {6 m. ret r i eveAct iveBody ( ) ;
7 t h i s . analyzeBody (m. getActiveBody ( ) ) ;
8 } e l s e {9 t h i s . analyzeBody (m. getActiveBody ( ) ) ;
10 }11 }12 }13 }14 }15
16 pr i va t e void analyzeBody (Body body ) {17 PatchingChain<Unit> methodStatements = body . getUni t s ( ) ;
18 I t e r a t o r<Unit> s t a t emen t s I t e r a t o r = methodStatements . s nap sho t I t e r a t o r ( ) ;
19 SootMethod currentMethod = body . getMethod ( ) ;
20 i f ( ! currentMethod . i sDec l a r ed ( ) ) {21 r e turn ;
22 }23 SootClass cu r r en tC la s s = currentMethod . g e tDec l a r ingC la s s ( ) ;
24 whi le ( s t a t emen t s I t e r a t o r . hasNext ( ) ) {25 Stmt statement = (Stmt ) s t a t emen t s I t e r a t o r . next ( ) ;
26 analyzeStatement ( body , currentMethod , currentClas s , statement ) ;
27 }28 }29
30 protec ted abs t r a c t void analyzeStatement (Body body ,
31 SootMethod currentMethod , SootClass currentClas s , Stmt statement ) ;
32
33 protec ted abs t r a c t boolean shou ldBeIn l ined ( SootMethod currentMethod ,
34 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) ;
35
36 protec ted void t ryToIn l i n e (Body body , SootMethod currentMethod ,
37 SootClass currentClas s , Stmt statement , InvokeExpr invokeExpress ion ) {38 SootMethod invokeMethod = invokeExpress ion . getMethod ( ) ;
39 i f ( shou ldBeIn l ined ( currentMethod , currentClas s , statement , invokeMethod ) ) {40 S i t e I n l i n e r . i n l i n e S i t e ( invokeMethod , statement , body . getMethod ( ) ) ;
41 }42
43 protec ted boolean i s S a f eTo In l i n e ( SootMethod currentMethod ,
44 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) {45 i f ( ! invokeMethod . hasActiveBody ( ) ) {46 r e turn f a l s e ;
47 }48 r e turn invokeMethod . getActiveBody ( ) i n s t an c e o f JimpleBody
49 && Inl inerSa fe tyManager . e n s u r e I n l i n a b i l i t y ( invokeMethod ,
50 statement , currentMethod , modi f i e rOpt ions ) ;
51 }52 }
Listing 4.1 Core loop of inliners in AbstractInliner.
4.2 UNNECESSARY ASPECTOF() REMOVER 49
1 pub l i c ab s t r a c t c l a s s S t a t i c I n l i n e r extends Abs t r a c t I n l i n e r {2 @Override
3 protec ted void analyzeStatement (Body body , SootMethod currentMethod ,
4 SootClass currentClas s , Stmt statement ) {5 i f ( statement i n s t an c e o f JInvokeStmt ) {6 JInvokeStmt invokeStatement = ( JInvokeStmt ) statement ;
7 InvokeExpr invokeExpress ion = invokeStatement . getInvokeExpr ( ) ;
8 i f ( invokeExpress ion i n s t an c e o f Stat ic InvokeExpr ) {9 t ryToIn l i n e ( body , currentMethod , currentClas s , statement , invokeExpress ion ) ;
10 }11 } e l s e i f ( statement i n s t an c e o f JAssignStmt ) {12 JAssignStmt ass ignStatement = ( JAssignStmt ) statement ;
13 Value value = ass ignStatement . getRightOp ( ) ;
14 i f ( va lue i n s t an c e o f Stat ic InvokeExpr ) {15 Stat ic InvokeExpr invokeExpress ion = ( Stat ic InvokeExpr ) va lue ;
16 t ryToIn l i n e ( body , currentMethod , currentClas s , statement , invokeExpress ion ) ;
17 }18 }19 }20 }
Listing 4.2 Static Method Inliner.
1 pub l i c ab s t r a c t c l a s s V i r t u a l I n l i n e r extends Abs t r a c t I n l i n e r {2 @Override
3 protec ted void analyzeStatement (Body body , SootMethod currentMethod ,
4 SootClass currentClas s , Stmt statement ) {5 i f ( statement i n s t an c e o f JInvokeStmt ) {6 JInvokeStmt invokeStatement = ( JInvokeStmt ) statement ;
7 InvokeExpr invokeExpress ion = invokeStatement . getInvokeExpr ( ) ;
8 i f ( invokeExpress ion i n s t an c e o f VirtualInvokeExpr ) {9 t ryToIn l i n e ( body , currentMethod , currentClas s , statement , invokeExpress ion ) ;
10 }11 } e l s e i f ( statement i n s t an c e o f JAssignStmt ) {12 JAssignStmt ass ignStatement = ( JAssignStmt ) statement ;
13 Value value = ass ignStatement . getRightOp ( ) ;
14 i f ( va lue i n s t an c e o f VirtualInvokeExpr ) {15 VirtualInvokeExpr invokeExpress ion = ( VirtualInvokeExpr ) va lue ;
16 t ryToIn l i n e ( body , currentMethod , currentClas s , statement , invokeExpress ion ) ;
17 }18 }19 }20 }
Listing 4.3 Instance Method Inliner.
4.2 UNNECESSARY ASPECTOF() REMOVER 50
affected join point, right above the body of the advice. If this call were not present, there
would be no reference to the aspect’s classfile in the classes affected by the advice.
Therefore, we developed an optimization that removes such unnecessary aspectOf()
calls, eliminating all references to the aspect’s classfile generated by advices. Algorithm 2
shows how the optimization works, and how it identifies which aspectOf() calls are un-
necessary by checking if the statement following the aspectOf() call is a pop instruction,
which discards the value at the top of the stack of the current method.
Algorithm 2: Unnecessary aspectOf() remover algorithm.
Input: Classes and aspects compiled by abc
Output: Classes and aspects without unnecessary aspectOf() calls
1 foreach c in the set of classes do
2 foreach method m in class c do
3 foreach instruction s in method m do
4 if s is an aspectOf() call then
5 s1 ←− instruction after s;
6 if s1 = ”pop” then
7 remove s and s1 from m;
8 end
9 end
10 end
11 end
12 end
This algorithm is specified at the bytecode level, unlike our other algorithms, which are
specified with the Jimple intermediate representation in mind. However, it is implemented
using a Jimple transformation, like all of our optimizations.
In Jimple, if the return value of a method call is being used, it will be in the right
value of a statement of the form “x = call()”, which is a subclass of AbstractStmt
called JAssignStmt. While iterating over every statement in a method, if we find a
JInvokeStmt that references a method with a return value, we know its return value
is being discarded (a pop instruction will follow the call in the bytecode). If it were
being used, it would be found as a JAssignStmt with a JInvokeStmt as its right value.
4.2 UNNECESSARY ASPECTOF() REMOVER 51
Therefore, our optimization only checks if any statement in a method body, not the right
value, is a JInvokeStmt that matches the call signature of the aspectOf() method, which
effectively identifies unnecessary aspectOf() calls.
Listing 4.4 shows the implementation of this algorithm. Line 8 checks whether the
statement is a JInvokeStmt, which means that its return value, if there is one, is being
discarded, while lines 11 and 13 check whether the method matches the signature of an
aspectOf() method generated by abc for each aspect, enabling its removal from the body
of the method analyzed in Line 14. This transformation is executed for every method in
the classfiles analyzed, eliminating all unnecessary aspectOf() calls.
This optimization can be applied to any AspectJ program compiled by abc, because
it will only remove calls to aspectOf() when their return value is being discarded, which
will not be the case if the advice is not inlined for any reasons, such as accessing private
members of the aspect or removing the compiler options that force inlining.
1 protec ted void inte rna lTrans form (Body body , S t r ing phaseName , Map opt ions ) {2 PatchingChain methodStatements = body . getUni t s ( ) ;
3 I t e r a t o r s t a t emen t s I t e r a t o r = methodStatements . s nap sho t I t e r a t o r ( ) ;
4
5 whi le ( s t a t emen t s I t e r a t o r . hasNext ( ) ) {6 Stmt statement = (Stmt ) s t a t emen t s I t e r a t o r . next ( ) ;
7
8 i f ( statement i n s t an c e o f JInvokeStmt ) {9 JInvokeStmt invokeStmt = ( JInvokeStmt ) statement ;
10 InvokeExpr invokeExpress ion = invokeStmt . getInvokeExpr ( ) ;
11 i f ( invokeExpress ion i n s t an c e o f Stat ic InvokeExpr ) {12 SootMethod invokeMethod = invokeExpress ion . getMethod ( ) ;
13 i f ( i sAspec tS ing l e tonAcce s s ( invokeMethod ) ) {14 methodStatements . remove ( statement ) ;
15 }16 }17 }18 }19 }
Listing 4.4 Implementation of the unnecessary aspectOf() remover algorithm.
4.2 UNNECESSARY ASPECTOF() REMOVER 52
4.2.1 Applying the optimization
In Listing 4.5 we see the example of after returning advice we use in Section 3.2.6.2.
We see in Listing 4.6 that the advice body is inlined, but the call AfterCall.aspectOf()
is unnecessary, since the aspect’s instance is not being used to call any methods at all,
being discarded in the context of this method. Note that the decompiler used to present
the source code of the optimized bytecode omits the this qualification from method calls,
which is optional when there is no name conflicts, thefore this difference from the original
code should be disregarded.
1 pub l i c c l a s s ClassWithMethods {2 pub l i c void af fectedMethod ( ) {3 t h i s . c a l l e e ( ) ;
4 }5 pub l i c void c a l l e e ( ) {6 }7 pub l i c void someMethod ( ) {8 }9 }
10
11 pub l i c aspect A f t e rCa l l {12 a f t e r ( ClassWithMethods c t h i s ) r e tu rn ing :
13 c a l l ( pub l i c void ClassWithMethods . c a l l e e ( ) )
14 && th i s ( c t h i s )
15 && withincode ( pub l i c void ClassWithMethods . af fectedMethod ( ) ) {16 c t h i s . someMethod ( ) ;
17 }18 }
Listing 4.5 after returning call advice example.
1 pub l i c void af fectedMethod ( ) {2 c a l l e e ( ) ;
3 Afte rCa l l . aspectOf ( ) ;
4 someMethod ( ) ;
5 }
Listing 4.6 Method affected by an after returning advice.
We can see the result of applying this optimization in Listing 4.7. The call to
aspectOf() is no longer present and the method affected by the advice does not ref-
erence the aspect’s classfile.
4.3 INTER-TYPE FIELD INITIALIZATION INLINER 53
1 pub l i c void af fectedMethod ( ) {2 c a l l e e ( ) ;
3 someMethod ( ) ;
4 }
Listing 4.7 Method affected by an after returning advice (optimized).
Since the aspect’s classfile is no longer referenced, it can be removed by ProGuard
from the final build in this exemple, given that the aspect only had this advice. This opti-
mization removes part of the overhead associated with advices, leaving only the overhead
generated by accessing private members of the class in the body of advices in priviliged
aspects, which is discussed in Section 4.5.
4.2.2 Correctness
Removing a call to aspectOf() left by inlined advices has no side effect at all, given that
all it does is return the singleton instance of the aspect, which is created when the aspect
classfile is loaded by the Virtual Machine (VM). Our optimization correctly checks for
the precondition that the return value of the aspectOf() call is being discarded, not
removing any calls if aspect’s instance is necessary, which is the case when it is accessed
through an aspectOf() call that is not followed by a pop instruction, making it not
removable by our optimization.
The applicability of this optimization is guaranteed if the advice has been inlined,
and makes no modification to the bytecode if the aspect’s instance is being used to call
an advice implementation method. This enables the application of the optimization to
any AspectJ program, even ones that have advices that access the aspect’s state, because
these advices will not be inlined, having no modification made by our optimization.
4.3 INTER-TYPE FIELD INITIALIZATION INLINER
As we saw in Section 3.2.2.2, having an inter-type field declaration add an initialized field
to a class, using abc, generates an overhead of having its initialization done by calling a
static initialization method in the aspect, which in turn calls a static method, also in the
aspect, that returns the initialization value of the field.
4.3 INTER-TYPE FIELD INITIALIZATION INLINER 54
We developed an optimization that moves the initialization of the inter-type field to
the target class, where the static initialization method is being called. It consists of two
steps, executed in this order: inlining the method that returns the initialization value and
inlining the initialization method in the aspect called by the affected class’ constructor.
The order of execution of the two steps of this optimization was chosen so that the
first pass is an inlining that happens only inside the aspect, making no modification to
the target class. In this step we remove the reference to the initialization value container
method within the field initizalion method in the aspect. The second step happens in
the target class, where we inline the call to the field initialization method, which does
not have any reference to the aspect class, seeing that the reference was removed by the
first step of the optimization. After the second step, the initialization of the inter-type
field will happen entirely in the target class, removing the overhead associated with the
inter-type field initialization methods generated by abc.
Algorithm 3: Inter-type field initialization inliner algorithm.
Input: Classes and aspects compiled by abc
Output: Aspects and classes with inter-type field initialization overhead removed
1 foreach c in the set of classes do
2 foreach method m in class c do
3 foreach statement s in method m do
4 if s contains a method call then
5 mc ←− method call in s;
6 if mc is call to an inter-type field initialzation method then
7 inline mc
8 end
9 end
10 end
11 end
12 end
Algorithm 3 shows how both steps of the optimization work. Line 6 of the algo-
rithm matches the call for both initialization methods. The algorithm specified is im-
plemented by two different classes, InitInliner and FieldInitInliner, the former
4.3 INTER-TYPE FIELD INITIALIZATION INLINER 55
implementing the first step of the optimization, while the latter implements the second
step. Both of them extend StaticInliner, from our inlining framework, and override the
shouldBeInlined method, implementing the verification that checks if the method being
called at any statement is part of an inter-type field initialization process. Listing 4.8
shows how InitInliner checks, using abc’s naming convention, if the method called is
one that returns the initialization value of inter-type field declarations. Listing 4.9 shows
how FieldInitInliner also uses abc’s naming convention to identify the call to the
method that performs the inter-type field initialization.
1 protec ted boolean shou ldBeIn l ined ( SootMethod currentMethod ,
2 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) {3 boolean i s I n t e rTyp eF i e l d I n i t = invokeMethod . getName ( ) . s tartsWith ( ” i n i t $ ” ) ;
4 boolean i s S a f eTo In l i n e = super . i s S a f eTo In l i n e ( currentMethod , cur rentClas s , statement ,
5 invokeMethod ) ;
6 r e turn i s I n t e rTyp eF i e l d I n i t && i sSa f eTo In l i n e ;
7 }
Listing 4.8 Init Inliner.
1 protec ted boolean shou ldBeIn l ined ( SootMethod currentMethod ,
2 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) {3 boolean i s I n t e rTyp eF i e l d I n i t = invokeMethod . getName ( ) . s tartsWith (
4 ” f i e l d i n i t $ ” ) ;
5 boolean i s S a f eTo In l i n e = super . i s S a f eTo In l i n e ( currentMethod , currentClas s , statement ,
6 invokeMethod ) ;
7 r e turn i s I n t e rTyp eF i e l d I n i t && i sSa f eTo In l i n e ;
8 }
Listing 4.9 FieldInit Inliner.
This optimization always removes the overhead associated with inter-type field decla-
rations, as long as the precondition that the initialization expression does not access the
aspect’s state, or any field or method from any other class that the target class cannot
access, is met.
4.3.1 Applying the optimization
In Listing 4.10 we see the same example of initialized inter-type attribute declaration we
have shown previously in Section 3.2.2.2, and Listings 4.11 and 4.12 show the decompiled
4.3 INTER-TYPE FIELD INITIALIZATION INLINER 56
code of class’ constructor calling the initialization method and the declaration of the
initialization methods in the aspect class after compilation.
1 pub l i c c l a s s BlankClass {2 }3
4 pub l i c aspect Attr ibuteAspect {5 pub l i c i n t BlankClass . x = 1 ;
6 }
Listing 4.10 Initialized inter-type field declaration example.
1 pub l i c c l a s s BlankClass {2 pub l i c i n t x ;
3
4 pub l i c BlankClass ( ) {5 Attr ibuteAspect . f i e l d i n i t $ 2 2 ( t h i s ) ;
6 }7 }
Listing 4.11 Decompiled bytecode of the class after initialized inter-type field insertion.
1 pub l i c s t a t i c void f i e l d i n i t $ 2 2 ( BlankClass paramBlankClass ) {2 paramBlankClass . x = in i t$x$14 ( paramBlankClass ) ;
3 }4
5 pub l i c s t a t i c i n t i n i t$x$14 ( BlankClass paramBlankClass ) {6 r e turn 1 ;
7 }
Listing 4.12 Inter-type field initialization methods in the aspect.
We can see the result of applying the optimization in Listing 4.13, where there is no
longer any reference to the aspect’s class and that the initialization of the field now takes
place entirely inside the class’ constructor. The first step of the optimization inlined
the call to the init$x$14 method in the fieldinit$22 method in the aspect, while the
second step inlined the call to the fieldinit$22 method in the BlankClass constructor.
Both initialization methods are still present in the aspect. However, since they are
no longer referenced by any class, the entire classfile of our example can be removed
by ProGuard. Aspects can have many inter-type declarations and advices, which might
4.3 INTER-TYPE FIELD INITIALIZATION INLINER 57
1 pub l i c c l a s s BlankClass {2 pub l i c i n t x ;
3
4 pub l i c BlankClass ( ) {5 x = 1 ;
6 }7 }
Listing 4.13 Optimized initialization of inter-type field declaration.
not all be optimizable. In such case, the inter-type field initialization methods that are
no longer referenced are removed from the aspect’s classfile by ProGuard, minimizing
the overhead but not as significantly as it could be if the aspect’s classfile was removed
as well. Nevertheless, this optimization effectively removes all overhead associated with
having an initialized inter-type field declaration.
4.3.2 Correctness
It is easy to see that the behavior of the program is preserved after applying the opti-
mization when the initialization value is an expression that can be correctly evaluated by
the class as if we had used it in the declaration of regular initialized field. However, if
the initialization expression accesses a private field of the aspect’s state, or any field and
method that cannot be directly accessed by the target class, ignoring this and performing
inlining process would generate incorrect bytecode, seeing that the target class cannot
access the referenced field or method directly.
We did not develop a specific check for these conditions. Instead, we use Soot’s built-
in methods to identify whether a method call can be safely inlined at its calling site,
which already verifies if anything called in the method to be inlined can be correctly
accessed within the context of the invoking class. Every initialized field inter-type dec-
laration on the product lines analyzed had simple initialization expressions, which can
be correctly evaluated at the target class, enabling the application of this optimization
while preserving the behavior of the program.
If this optimization is applied to AspectJ programs that have inter-type field decla-
rations which have initialization expressions that cannot be evaluated correctly in the
target class, its initialization methods will not be inlined because Soot’s inline safety
4.4 INTER-TYPE METHOD INLINER 58
checker will return that they cannot be inlined, which does not allow our optimization to
perform any modification.
4.4 INTER-TYPE METHOD INLINER
As we saw in Section 3.2.5, an inter-type method declaration does not simply add the
method to the target class, as expected. In fact, it creates an indirection, only necessary
for debugging purposes, by having a method declared with the name of the inter-type
method in the target class, which does not contain the inter-type method’s body. Instead,
it calls a method in the aspect that contains the inter-type method’s body. We developed
an optimization which removes this indirection, inlining the placeholder method that
contains the body of the inter-type method.
Algorithm 4 shows how the optimization goes through the program to identify which
method calls are referencing inter-type method body placeholders. We used abc’s naming
convention along with a check of expected parameter types and quantity to identify which
method calls were targetting placeholders in aspect classfiles.
This algorithm does not enter an infinite loop state for recursive methods because
the statements inlined from the placeholder’s body at line 7 are not analyzed for further
inlining. The statement analyzed after the inlined call is the one that was after the call
before it was inlined. Also, more importantly, the inter-type method placeholder does
not reference itself when there is recursion. Instead, it calls the method in the target
class, which means that when it is inlined, it will not be referencing the placeholder in
the aspect.
Listing 4.14 shows the implementation of line 7 of Algorithm 4. We can see the name
verification in line 13 and a check to see if the the method being called is not in the same
class as the current class in line 16. The method checkParameterTypesEquality, in line
15, correspondes to the match part of the algorithm and checks if the parameters of the
invoked method match the expected parameters of an inter-type method.
When the invoked method is not static, it checks if the first parameter has the same
type as the declaring class of the current method and if the remaining parameters match
the parameters of the current method. If the invoked method is static, it does not need
to pass an instance of the current class for the placeholder, therefore, both methods must
4.4 INTER-TYPE METHOD INLINER 59
Algorithm 4: Inter-type method inliner algorithm.
Input: Classes compiled by abc
Output: Classes with inter-type method bodies in the target class
1 foreach c in the set of classes do
2 foreach method m in class c do
3 foreach statement s in method m do
4 if s contains a method call then
5 mc ←− method call in s;
6 if name(m) = name(mc) and parameters(m) match parameters(mc)
and declaring-class-of(mc) != c then
7 inline mc;
8 end
9 end
10 end
11 end
12 end
have the same number of parameters and with the same types.
This parameter equivalence verification process is shown in Listing 4.15. Line 14
shows the check for the extra parameter, if the invoked method is not static, and lines 22
and 23 show the check for type equality of the remaining parameters.
Inlining the placeholders that abc generates for inter-type method declarations re-
moves the overhead associated with inter-type method declarations. The placeholders
can always be inlined as long as the inter-type method does not access private state of
the aspect or any fields or methods from any other class that cannot be directly accessed
by the target class. This is verified by Soot’s inlining safety checker we use to ensure that
method calls can be properly inlined.
4.4.1 Applying the optimization
In Listing 4.16 we see an example of an inter-type method declaration which is recursive.
Listings 4.17 and 4.18 show, respectively, the decompiled target class of the inter-type
4.4 INTER-TYPE METHOD INLINER 60
1 protec ted boolean shou ldBeIn l ined ( SootMethod currentMethod ,
2 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) {3 boolean isInterTypeMethodImplementation = f a l s e ;
4
5 i f ( ! invokeMethod . hasActiveBody ( ) ) {6 t ry {7 invokeMethod . re t r i eveAct iveBody ( ) ;
8 } catch ( RuntimeException e ) {9 r e turn f a l s e ;
10 }11 }12
13 i f ( currentMethod . getName ( ) . equa l s ( invokeMethod . getName ( ) )
14 && invokeMethod . hasActiveBody ( )
15 && checkParameterTypesEquality ( invokeMethod , currentMethod )
16 && currentMethod . g e tDec l a r i ngC la s s ( ) != invokeMethod . g e tDec l a r ingC la s s ( ) ) {17 i f ( ! currentMethod . i s S t a t i c ( ) ) {18 Type f i r s tParameterType = (Type ) invokeMethod . getParameterTypes ( ) . get (0 ) ;
19 i f ( f i r s tParameterType i n s t an c e o f RefType ) {20 RefType refType = (RefType ) f i r s tParameterType ;
21 SootClass f i r s tPa ramet e rC l a s s = refType . ge tSootClas s ( ) ;
22 i sInterTypeMethodImplementation = f i r s tPa ramet e rC l a s s == cur r en tC la s s ;
23 }24 } e l s e {25 i sInterTypeMethodImplementation = true ;
26 }27 }28
29 boolean i s S a f eTo In l i n e = th i s . i s S a f eTo In l i n e ( currentMethod , currentClas s , statement ,
30 invokeMethod ) ;
31 r e turn isInterTypeMethodImplementation && i sSa f eTo In l i n e ;
32 }
Listing 4.14 Inter-type Method Inliner Implementation.
4.4 INTER-TYPE METHOD INLINER 61
1 pr i va t e boolean checkParameterTypesEquality ( SootMethod invokeMethod ,
2 SootMethod currentMethod ) {3 boolean containsExtraParameter = invokeMethod . getParameterCount ( ) ==
4 currentMethod . getParameterCount ( ) + 1 ;
5
6 boolean parameterTypesEqual = f a l s e ;
7 L i s t invokedParameterTypes = new LinkedLis t ( invokeMethod . getParameterTypes ( ) ) ;
8 i f ( ! currentMethod . i s S t a t i c ( ) && containsExtraParameter ) {9 Type f i r s tParameterType = (Type )
10 invokeMethod . getParameterTypes ( ) . get (0 ) ;
11 i f ( f i r s tParameterType i n s t an c e o f RefType ) {12 RefType refType = (RefType ) f i r s tParameterType ;
13 SootClass f i r s tPa ramet e rC l a s s = refType . ge tSootClas s ( ) ;
14 i f ( f i r s tPa ramet e rC l a s s != cur r en tC la s s ) {15 r e turn f a l s e ;
16 }17 } e l s e {18 r e turn f a l s e ;
19 }20 invokedParameterTypes . remove (0 ) ;
21 }22 parameterTypesEqual = invokedParameterTypes . equa l s ( currentMethod
23 . getParameterTypes ( ) ) ;
24
25 r e turn parameterTypesEqual ;
26 }
Listing 4.15 Check for parameters equivalence.
declaration, and the placeholder method in the aspect.
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {3 new BlankClass ( ) . x ( ) ;
4 }5 }6
7 pub l i c aspect IntertypeMethod {8 pub l i c i n t BlankClass . x ( ) {9 r e turn t h i s . x ( ) + 1 ;
10 }11 }
Listing 4.16 Inter-type method declaration example.
We can see the result of applying this optimization in Listing 4.19, where we have the
4.4 INTER-TYPE METHOD INLINER 62
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] paramArrayOfString ) {3 new BlankClass ( ) . x ( ) ;
4 }5
6 pub l i c i n t x ( ) {7 r e turn IntertypeMethod . x ( t h i s ) ;
8 }9 }
Listing 4.17 Declaration of inter-type method on BlankClass (abc).
1 pub l i c s t a t i c i n t x ( BlankClass paramBlankClass ) {2 r e turn paramBlankClass . x ( ) + 1 ;
3 }
Listing 4.18 Inter-type method implementation in the aspect (abc).
inter-type method with its body in the target class, with no reference whatsoever to the
aspect’s classfile. We can also see that it is inlined correctly, despite being recursive.
1 pub l i c c l a s s BlankClass {2 pub l i c s t a t i c void main ( S t r ing [ ] paramArrayOfString ) {3 new BlankClass ( ) . x ( ) ;
4 }5
6 pub l i c i n t x ( ) {7 r e turn x ( ) + 1 ;
8 }9 }
Listing 4.19 Optimized initialization of inter-type attribute declaration.
The placeholder method is still present in the aspect. However, since it is no longer
referenced by any class and the inter-type method was the only construct in the aspect,
the entire aspect classfile can be removed by ProGuard. This optimization effectively
removes the overhead associated with having an inter-type method declaration.
4.4.2 Correctness
There are only two cases where it is not possible to inline inter-type methods, when they
access the private state of the aspect or a method or field from any other class that cannot
4.5 ACCESSOR INLINER 63
be accessed by the target class. Our optimization does not inline inter-type methods that
have these restrictions, since we use Soot’s inline safety checker.
When the inter-type method does not violate this precondition, it follows that it
must obey the same restrictions a normal method declared on the target class would.
Therefore, inlining the placeholder method results in a code equivalent to having the
method declared in the target class.
Since it is possible for an inter-type method to access private members of the target
class, the placeholder method uses accessors to get and set the values of the private fields
or to call private methods. When the inter-type method does not access private members
of the target class, the optimization completely removes the overhead of the inter-type
method. However, when this is not the case, our optimization inlines the placeholder
preserving the accessors, which are removed in the optimization described in the next
section.
4.5 ACCESSOR INLINER
Advices and inter-type method declarations can access private attributes, when their
aspect is declared with the modifier privileged. However, the way the access to these
private members is provided generates overhead. As seen in Section 3.2.6.1, for each
private attribute accessed, two accessor methods are created, while one accessor method
is created for each private method accessed.
When advices are inlined there is no need for accessors, given that the advice’s body
will be in the target class. There is also no need for accessors in inter-type method decla-
rations after our optimization described in Section 4.4 has been applied to the program’s
bytecode. However, some private members accessed may not be in the target class of the
inter-type method or advice, which means that these accessors must not be inlined.
Our optimization simply inlines calls to accessors methods when they are made inside
a method in the same class in which the accessor is defined. This optimization must
be executed after the inter-type method inliner has been applied, in order to have the
method’s body already in the target class, a precondition of this optimization.
Algorithm 5 shows how the optimization goes through the program to identify calls
to accessors that can be inlined. It uses abc’s accessors naming convention to identify
4.5 ACCESSOR INLINER 64
Algorithm 5: Accessor inliner algorithm.
Input: Aspects and classes compiled by abc
Output: Aspects and classes with accessor calls inlined
1 foreach c in the set of classes do
2 foreach method m in class c do
3 foreach statement s in method m do
4 if s contains a method call then
5 mc ←− method call in s;
6 isAccessor ←− mc starts with accessor$ or get$accessor$ or
set$accessor$;
7 t ←− declaring-class-of(mc);
8 if isAccessor and c = t then
9 inline s;
10 end
11 end
12 end
13 end
14 end
whether the target of a method call is an accessor or not. It also checks if the call is
being made in the same class as the one where the accessor is declared, to prevent inlining
accessors from private members of other classes.
This algorithm is implemented by a class called UnnecessaryAccessorsRemover, that
extends VirtualInliner, from our inlining framework. Listing 4.20 shows the method
that implements lines 6, 7 and 8 of the algorithm. We can see in lines 3 to 6 of the
implementation the comparison of the invoked method’s name with the expected name
of accessors, and in lines 8 and 9 we can see the check for whether the accessor is being
called in the same class it is located. These verifications along with the inlining safety
check ensure that the code inlined will be valid.
This optimization removes the overhead of accessing private members of the target
classes affected by inter-type methods and advices. However, it is not possible to remove
the overhead associated with the access to private members of classes different than the
4.5 ACCESSOR INLINER 65
target class of the inter-type methods or advices. The accessor being declared in the
same class where it is being used is a precondition which is properly checked by our
optimization.
1 protec ted boolean shou ldBeIn l ined ( SootMethod currentMethod ,
2 SootClass currentClas s , Stmt statement , SootMethod invokeMethod ) {3 St r ing methodName = invokeMethod . getName ( ) ;
4 boolean isMethodAccessor = methodName . startsWith ( ” ac c e s s o r$ ” ) ;
5 boolean i sGetAcces sor = methodName . startsWith ( ” g e t$ac c e s s o r$ ” ) ;
6 boolean i sS e tAcc e s s o r = methodName . startsWith ( ” s e t$a c c e s s o r$ ” ) ;
7
8 boolean is InvokeInSameClass = invokeMethod . g e tDec l a r ingC la s s ( )
9 . equa l s ( cu r r en tC la s s ) ;
10 r e turn ( isMethodAccessor | | i sGetAcces sor | | i s S e tAcc e s s o r )
11 && isInvokeInSameClass
12 && th i s . i s S a f eTo In l i n e ( currentMethod , currentClas s , statement ,
13 invokeMethod ) ;
14 }
Listing 4.20 Implementation of the accessor inliner optimization.
4.5.1 Applying the optimization
In Listing 4.21 we see an example of an advice that accesses both, a private field and a
private method, and Listing 4.22 shows the decompiled bytecode of the class affected by
the advice, where we have calls to accessor methods that are unnecessary, given that the
private field and method can be accessed directly.
We can see the result of applying our optimization in Listing 4.23, where we have the
advice body inlined, accessing the private field and method directly. The accessors are
still present in the class, but they are no longer referenced, which enables their removal
by ProGuard.
4.5.2 Correctness
Seeing that the accessors are being used in the same class as the private members they
are providing access to, it follows that inlining any calls to these methods will result
in a behavior-preserving bytecode. The optimization has two preconditions: it must be
executed after our inter-type method inliner optimization, described in Section 4.4, has
4.5 ACCESSOR INLINER 66
1 pub l i c c l a s s ClassWithMethods {2 pr i va t e i n t x ;
3
4 pr i va t e void privateMethod ( ) {5 }6
7 pub l i c void publicMethod ( ) {8 System . out . p r i n t l n ( ” pub l i c ” ) ;
9 }10 }11
12 pub l i c p r i v i l e g e d aspect Pr ivateAccessAspect {13 be f o r e ( ClassWithMethods c t h i s ) :
14 execut ion ( pub l i c void ClassWithMethods . publicMethod ( . . ) )
15 && th i s ( c t h i s ) {16 c t h i s . x = c t h i s . x + 1 ;
17 c t h i s . privateMethod ( ) ;
18 }19 }
Listing 4.21 Access to private members example.
1 pub l i c c l a s s ClassWithMethods {2 pr i va t e i n t x ;
3 pr i va t e void privateMethod ( ) {4 }5 pub l i c i n t ge t$acce s so r$x$17 ( ) {6 r e turn t h i s . x ;
7 }8 pub l i c i n t s e t$acc e s so r$x$18 ( i n t paramInt ) {9 t h i s . x = paramInt ;
10 r e turn paramInt ;
11 }12 pub l i c void accessor$pr ivateMethod$19 ( ) {13 privateMethod ( ) ;
14 }15 pub l i c void publicMethod ( ) {16 PrivateAccessAspect . aspectOf ( ) ;
17 s e t$acc e s so r$x$18 ( ge t$acce s so r$x$17 ( ) + 1) ;
18 accessor$pr ivateMethod$19 ( ) ;
19 System . out . p r i n t l n ( ” pub l i c ” ) ;
20 }21 }
Listing 4.22 Decompiled bytecode of the class affected by advice with access to private
members.
4.5 ACCESSOR INLINER 67
1 pub l i c c l a s s ClassWithMethods {2 pr i va t e i n t x ;
3 pr i va t e void privateMethod ( ) {4 }5 pub l i c i n t ge t$acce s so r$x$17 ( ) {6 r e turn t h i s . x ;
7 }8 pub l i c i n t s e t$acc e s so r$x$18 ( i n t paramInt ) {9 t h i s . x = paramInt ;
10 r e turn paramInt ;
11 }12 pub l i c void accessor$pr ivateMethod$19 ( ) {13 privateMethod ( ) ;
14 }15 pub l i c void publicMethod ( ) {16 PrivateAccessAspect . aspectOf ( ) ;
17 t h i s . x += 1 ;
18 privateMethod ( ) ;
19 System . out . p r i n t l n ( ” pub l i c ” ) ;
20 }21 }
Listing 4.23 Decompiled bytecode of the class affected by advice with access to private
members (optimized).
been executed, and that the call to the accessor must be located in the same class where
the accessor is declared, which is properly implemented as we saw in Listing 4.20.
The ordering of the optimizations is specified in the Main class of our optimizations
package, which is a wrapper for Soot’s Main class, adding our optimizations to the proper
transformations package. We can see the code of our Main class in Listing 4.24, where
we have our optimizations being scheduled for execution. The unnecessary aspectOf()
remover is added without any ordering, since it can be executed independent of other
optimizations, but the other optimizations are scheduled in the following order:
1. Inter-type method inliner
2. Init inliner (first step of inter-type field initialization inliner)
3. FieldInit inliner (second step of inter-type field initialization inliner)
4. Accessor inliner
4.5 ACCESSOR INLINER 68
1 pub l i c c l a s s Main {2 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {3 i f ( a rgs . l ength == 0) {4 System . out . p r i n t l n ( ”Syntax : java ”
5 + ” soot . examples . i n s t rument c l a s s . Main −−app mainClass ”
6 + ” [ soot opt ions ] ” ) ;
7 System . e x i t (0 ) ;
8 }9 PhaseOptions . v ( ) . setPhaseOption ( ” jb ” , ” enabled : t rue ” ) ;
10 PhaseOptions . v ( ) . setPhaseOption ( ”cg” , ” enabled : o f f ” ) ;
11 PhaseOptions . v ( ) . setPhaseOption ( ”wjop” , ” enabled : o f f ” ) ;
12 PhaseOptions . v ( ) . setPhaseOption ( ”wjop . s i ” , ” enabled : o f f ” ) ;
13 PackManager . v ( ) . getPack ( ”wjtp” ) . add (
14 new Transform ( ”wjtp . itmt ” , InterTypeMethodInl iner . v ( ) ) ) ;
15 PackManager . v ( ) . getPack ( ”wjtp” ) . i n s e r tA f t e r (
16 new Transform ( ”wjtp . i i ” , I n i t I n l i n e r . v ( ) ) , ”wjtp . itmt ” ) ;
17 PackManager . v ( ) . getPack ( ”wjtp” ) . i n s e r tA f t e r (
18 new Transform ( ”wjtp . f i ” , F i e l d i n i t I n l i n e r . v ( ) ) , ”wjtp . i i ” ) ;
19 PackManager . v ( ) . getPack ( ”wjtp” ) . i n s e r tA f t e r (
20 new Transform ( ”wjtp . uar” , UnnecessaryAccessorsRemover . v ( ) ) , ”wjtp . f i ” ) ;
21 PackManager . v ( ) . getPack ( ” j tp ” ) . add (
22 new Transform ( ” j tp . uaor ” , UnnecessaryAspectOfRemover . v ( ) ) ) ;
23 soot . Main . main ( args ) ;
24 }25 }
Listing 4.24 Optimizations scheduling.
The optimizations described in this chapter cover all the constructs found to generate
overhead in the hybrid version of the product lines analyzed. As expected, they increase
the compilation time of any program, but the benefits that can be gained from using
them trumps some minutes increase in compilation time, depending on the size of the
system. Our optimizations should be used when the system is ready to be deployed and
debugging information is no longer necessary, at the end of the software development.
It is important to note that we believe that applying our optimizations in programs
that use the constructs that were not analyzed in this work will not result in incorrect
bytecode or any changes in execution behavior. Our optimizations have strict precon-
ditions that ensure that they will only be applied when these conditions are valid. If
any construct interferes with these preconditions, our optimizations will leave the code
unchanged. In the next section we present the results obtained after performing these
optimizations in real systems.
CHAPTER 5
EVALUATION
“Study while others are sleeping; work while others are loafing; prepare
while others are playing; and dream while others are wishing.”
—WILLIAM A. WARD
In this chapter we present the evaluation of the optimizations we developed. Our goal
with these optimizations is to eliminate the overhead generated by AspectJ compilers in
Product Lines that use aspects to fully, or partially, structure variations. We identified
this overhead in Section 3.1 and investigated its motives in Section 3.2.
In our evaluation we use two SPLs as benchmarks for the comparison of size overhead
when they are compiled without and with our optimizations. The first SPL is BestLap,
which was the SPL used in Section 3.1 to identify that there is, in fact, size overhead
when AspectJ is used to structure code variations. The second is MobileMedia, a SPL
for applications that manipulate photo, music and video on mobile devices.
BestLap and Juggling, two mobile game SPLs developed by the same company, were
used to elicit the list of AspectJ constructs inspected to identify those that generate
overhead. Therefore, we expect our goal to be achieved completely for BestLap, given
that our optimizations cover all AspectJ constructs used in this SPL.
We present the results of the evaluation for BestLap and MobileMedia, along with a
discussion of the similarities and differences between them, and performance benchmarks
in the following sections.
5.1 BESTLAP
BestLap is a SPL of mobile games developed for dozens of devices. Figure 5.1 shows
the feature model1 of BestLap, which has several mandatory, optional and alternative
1Feature models designed with the pure::variants Community (http://www.pure-systems.com/)
69
5.1 BESTLAP 70
features. The instances of MobileMedia are defined as selections of these featues, with
each instance having a set of art assets, preprocessing tags to be used when compiling the
code, AspectJ files to be included in the build, in the case of the hybrid version, among
other build parameters.
Figure 5.1 Feature Model of the BestLap Product Line
Each instance has a unique identification name and can be installed in several devices
from the same manufacturer which were found to share enough similarities (e.g., identical
screen size) that justify using the same final product package, a jar file, in each device.
5.1 BESTLAP 71
MOT1, for instance, is the identification name of an instance that denotes a family, i.e.,
a set, of low end devices from Motorola that can be considered equal for purposes of
product generation. We modified the build process of BestLap, illustrated in Figure 3.1,
to include the execution of our optimizations after the compilation process, but before
the optimization and obfuscation step.
All optimizations discussed in the previous chapter were applied to the BestLap prod-
uct line, and we can see the results obtained in Table 5.1. Each line has an instance of the
product lines with its ID in first column, the size for the original version in the second
column, the size of the hybrid version in the third column and the size of the hybrid
version with our optimizations in the last column. All builds in the table were compiled
with abc.
With our optimizations, we managed to decrease the average build size of the hybrid
version from 81.107 bytes to 73.686 bytes, which makes it 2 bytes smaller (-0,00135708%)
than the original version, on average. We can consider this a complete elimination of the
overhead. We mentioned in Section 3.1 that the hybrid S40 instance was not installable in
the family’s devices due to the overhead, which made it larger than 64KB, the maximum
application size supported by devices in this family. With our optimizations, the hybrid
S40 instance is once again installable in its devices, being slightly smaller than 64KB.
It is important to note that each individual build of the hybrid version with the
optimizations does not have exactly the same size as the original version. In fact, seven
builds were slightly smaller and eight builds were slightly bigger. The S40 build was
the one with the largest overhead remaining, with its optimized hybrid version being
0.56% larger than the original version, while the S40M2 version was the one that not
only removed the overhead but decreased the application size the most, when compared
to the original version, with its optimized hybrid version being 0.50% smaller than the
original version.
We believe this variation in the optimized hybrid version in being slightly smaller or
bigger than the original version to be the result of fine-grained Soot or Proguard opti-
mizations having their effectiveness affected by the inlining process of our optimizations,
which, at bytecode level, might not leave the code 100% equal, line by line, to the one
generated when compiling the code with conditional compilation of the original version.
However, this is very hard to verify due to the sheer number of optimizations executed
5.1 BESTLAP 72
Build ID Original Hybrid Hybrid (optimized)
MOT1 70,952 78,276 70,639
MOT2 83,327 90,675 83,460
MOT3 70,964 78,431 70,908
S40 63,492 69,597 63,847
S40M2 71,032 77,471 70,675
S40M2V3 70,537 77,325 70,597
S60M1 83,625 90,826 83,776
S60M2 82,499 89,823 82,687
SAM1 64,792 70,171 64,781
SAM2 78,707 82,753 78,514
SE02 82,359 88,564 82,319
SE03 70,618 77,221 70,532
SE04 70,563 77,198 70,533
SIEM3 71,312 78,547 71,355
SIEM4 70,533 77,865 70,674
Arithmetic Mean 73,687 80,316 73,686
Arithmetic mean size
increase in relation to
original
0% 9.00% 0.00%
Table 5.1 Comparison (in bytes) of the original version of BestLap against the aspects version
by Soot and Proguard making the bytecode very hard to read.
The box plot in Figure 5.2 shows that there is barely any difference between the
original version and the optimized hybrid version. The optimized hybrid version has a
slightly smaller median, despite having a slightly larger maximum value, while the original
version has a smaller minimum value.
Table 5.2 shows the number of applications of each optimization in each instance
of BestLap. The SAM1 and SAM2 instances are the ones with the lowest number of
applications due to the fact that they do not have the optional feature Arena, which
accounts for a large number of AspectJ constructs. We can see that, in most instances,
5.2 MOBILEMEDIA 73
Figure 5.2 Box plot of the original, hybrid and optimized versions of the BestLap product line
the most applied optimization was the Accessor Inliner, meaning that advices and inter-
type methods were frequently accessing private members of the classes.
We can also determine the number of advices, initialized inter-type fields and inter-
type methods by the number of applications of the respective optimizations. In each
instance of BestLap after the optimization and the execution of ProGuard, there were
no aspect classfiles remaining on the system, showing that our optimizations made them
unnecessary. We can see that we reached our objective with the application of our
optimizations to the hybrid version of the BestLap product line. In the next section we
evaluate another product line to see the benefits gained with our optimizations.
5.2 MOBILEMEDIA
The other SPL we used to evaluate our optimizations is MobileMedia, a product line for
applications that manipulate photo, music and video on mobile devices. Figure 5.3 shows
MobileMedia’s feature model, where we can see that it has some mandatory, optional
and alternative features. The mandatory features of MobileMedia are applicable to the
instances for all devices. The optional and alternative features are enabled on instances
for devices that provide the required API. We can see that MobileMedia has much fewer
features than BestLap.
Like BestLap, MobileMedia also has a version with conditional compilation as varia-
5.2 MOBILEMEDIA 74
Build ID Unnecessary
aspectOf()
Remover
Inter-type
Method Inliner
Inter-type Field
Initialization In-
liner
Accessor
Inliner
MOT1 11 29 27 39
MOT2 11 29 22 39
MOT3 11 29 23 39
S40 13 24 21 38
S40M2 9 29 27 39
S40M2V3 9 26 23 39
S60M1 15 25 24 73
S60M2 15 26 24 73
SAM1 8 7 9 7
SAM2 5 8 10 8
SE02 9 26 20 37
SE03 9 26 23 37
SE04 9 26 23 37
SIEM3 26 26 23 39
SIEM4 29 29 27 39
Table 5.2 Number of optimizations applications in the hybrid version of BestLap
tion structuring mechanism and another with AspectJ fulfilling this role. However, unlike
BestLap, the AspectJ version of MobileMedia is not hybrid. There is no preprocessed
code in the AspectJ version, and the aspects were not derived using refactorings, it was
up to the developers to use any AspectJ construct they saw fit to structure the variations,
while preserving the behavior of the program.
Due to this freedom developers had when developing the AspectJ version of Mobile-
Media, it happens that MobileMedia has a few aspects with state, which does not enable
the application of our optimizations for constructs that access this state. The statefulness
of these aspects is not optimal for the application of our optimizations, since some of the
optimizations have specific preconditions stating that advice state must not be accessed.
However, we found that, in all cases, this state could have been part of the class that
5.2 MOBILEMEDIA 75
Figure 5.3 Feature Model of the MobileMedia Product Line
the aspect was modifying. MobileMedia also has a few advices with quantification, that
is, they apply to more than one join point. This means that, depending on the size of
the advice and the number of applications, inlining some advices might result in a larger
bytecode size of the program.
In order to illustrate that it was not necessary to have state in the aspects, Listing 5.1
shows part of the code of the aspect CapturePhotoAspect, which modifies the class
CaptureVideoScreen adding new command to capture photos in line 14, in an after
advice. The command, declared as an instance field of the aspect in line 3, could have
been declared as an inter-type field of CaptureVideoScreen, thus enabling our inter-type
field initialization inliner, the inlining of the advice by abc and our aspectOf() remover.
It becomes even more clear that it should have been an inter-type field seeing the orig-
inal declaration of the command in the conditional compilation version of MobileMedia,
in Listing 5.2. It was declared as an instance field of CaptureVideoScreen, therefore a
refactoring of this declaration to AspectJ would have it as an inter-type field declaration.
We analyzed all occurences of state in the aspects of MobileMedia and found that all
of them could have been declared as inter-type fields and inter-type methods. We found
instance methods in a few aspects, but they were accessing these same fields that could
5.2 MOBILEMEDIA 76
1 // r e s t o f the code from th i s aspect omitted
2
3 Command takephoto = new Command( ”Take photo” , Command.EXIT, 1) ;
4
5 pub l i c f i n a l s t a t i c i n t CAPTUREPHOTO = 1 ;
6
7 po intcut con s t ruc to r ( ) : c a l l ( CaptureVideoScreen . new ( . . ) ) ;
8
9 a f t e r ( ) r e tu rn ing ( CaptureVideoScreen l i s t S c r e e n ) : c on s t ruc to r ( ) {10 System . out . p r i n t l n ( ”<* CapturePhotoAspect . a f t e r ( ) new CaptureVideoScreen ( ) *> ”
11 + l i s t S c r e e n . typesc r een + ”=” + CAPTUREPHOTO) ;
12 // [NC] Added in the s c ena r i o 08
13 i f ( l i s t S c r e e n . typesc reen == CAPTUREPHOTO) {14 l i s t S c r e e n . addCommand( takephoto ) ;
15 }16 }
Listing 5.1 Aspect for the photo feature adding a new command to the screen
1 pub l i c c l a s s CaptureVideoScreen extends GameCanvas {2 // r e s t o f the code omitted
3
4 //#i f d e f capturePhoto
5 // [NC] Added in the s c ena r i o 08
6 pr i va t e Command takephoto = new Command( ”Take photo” , Command.EXIT, 1) ;
7 //#end i f
8
9 // r e s t o f the code omitted
10 }
Listing 5.2 Command in CaptureVideoScreen in the conditional compilation version of
MobileMedia
have been declared as inter-type fields. It is interesting to notice that we found a very
clear example of the fact that developers implemented an aspect with state that could
have been stateless, which illustrates that, even when implementing the same logic, the
developers used different, albeit equivalent, approaches.
In the example we found, a very similar code in two aspects only differs in the dec-
laration of a field and two methods as inter-type or as instance members of the aspect.
Listing 5.3 shows a snippet of code from the aspect PhotoAndMusicAndVideoAspect that
shows the declaration of a field called mainscreen, in line 6, as an inter-type field of the
class ScreenSingleton. Its get and set methods are declared as inter-type methodos
5.2 MOBILEMEDIA 77
of ScreenSingleton.
The aspect PhotoAndMusicAspect, shown in Listing 5.4, has an almost identical code.
The only difference is that the mainscreen field is declared as an instance field of the
aspect, instead of an inter-type field of ScreenSingleton, which resulted in its get and
set methods also being inter-type declarations. These declarations of field and methods
as instance members of the aspect do not enable the application of our optimizations.
1 // Rest o f the code omitted
2
3 // ******** ScreenS ing l e ton ********* //
4
5 // [NC] Added in the s c ena r i o 07
6 pr i va t e SelectTypeOfMedia Sc r eenS ing l e ton . mainscreen ;
7
8 pub l i c SelectTypeOfMedia Sc r eenS ing l e ton . getMainMenu ( ) {9 r e turn mainscreen ;
10 }11
12 pub l i c void Sc r eenS ing l e ton . setMainMenu ( SelectTypeOfMedia s c r e en ) {13 mainscreen = sc r e en ;
14 }
Listing 5.3 Main menu screen singleton declaration in PhotoAndMusicAndVideoAspect
1 // Rest o f the code omitted
2
3 // ******** ScreenS ing l e ton ********* //
4
5 // [NC] Added in the s c ena r i o 07
6 pr i va t e SelectTypeOfMedia mainscreen ;
7
8 pub l i c SelectTypeOfMedia getMainMenu ( ) {9 r e turn mainscreen ;
10 }11
12 pub l i c void setMainMenu ( SelectTypeOfMedia s c r e en ) {13 mainscreen = sc r e en ;
14 }
Listing 5.4 Main menu screen singleton declaration in PhotoAndMusicAspect
Nevertheless, it is important to see what kind of benefit can be achieved by applying
our optimizations to a product line that differs from the ones we inspected for AspectJ
5.2 MOBILEMEDIA 78
constructs. It is also important to remember that our optimizations will not perform any
modification to the bytecode of AspectJ constructs that access the state of the aspect,
given that we have preconditions properly implemented in order to prevent these incorrect
modifications from happening.
Unlike BestLap, in which each instance had approximately the same number of as-
pects, MobileMedia has more optional features, meaning that some builds have fewer
aspects than others. The A01 instance, for example, has 9 aspects enabled, while the
ABC03 instance, which has all optional features enabled, has 31 aspects enabled. Mo-
bileMedia also differs from BestLap in that features that can be enabled in the instances
also contain Java classes to implement them alongside the aspects. The optional feature
to send media by SMS, for instance, has one aspect and six classes that implement it.
The presence of classes as variations combined with the aspects is irrelevant, given that
the conditional compilation version has the same classes. MobileMedia is also smaller
than Bestlap, having approximately 5 KLOC, while the original version of BestLap has
almost 20 KLOC.
Table 5.3 shows which optional and alternative features are included in each of the
instances defined in MobileMedia. We use all instances that were already defined in Mo-
bileMedia for our evaluation. While generating a build of each instance of MobileMedia,
we found that the C03 instance only had a build specification in the AspectJ version.
For some reason there was no build specification for the C03 instance in the original ver-
sion. For this reason, we created a build specification in the original version to define the
C03 instance, in order to be able to compile the instance and compare it to its AspectJ
version.
We removed some media files that were included in MobileMedia’s instance package
because they were accounting for a very large percentage of the build size. Since we are
focusing on reducing bytecode size, it provides a better view of the difference in code
size when we exclude such files from the build. As we can see in Table 5.4, the build
size of MobileMedia’s instances, containing only the classfiles, in the unoptimized aspects
version is, on average, 34.54% larger than the conditional compilation version.
When applying our optimizations, the average size of MobileMedia’s instances is, on
average, 17,96% larger than the preprocessed version, which is approximately 50% less
overhead than the unoptimized version. Figure 5.4 shows the box plot of our results for
5.2 MOBILEMEDIA 79
Instance Optional and Alternative Features
A01 Photo
A02 Photo, Sorting, Favorites
A03 Photo, Sorting, Favorites, Copy Media, SMS Photo
Transfer, Capture
B01 Music
B02 Music, Sorting, Favorites
B03 Music, Sorting, Favorites, Copy Media
C01 Video
C02 Video, Sorting, Favorites
C03 Video, Sorting, Favorites, Copy Media, Capture
ABC03 Photo, Video, Music, Sorting, Favorites, Copy Media,
SMS Transfer, Capture
Table 5.3 Optional and Alternative Features enabled in MobileMedia’s instances
MobileMedia. We can see that there were no minimum outliers. However, the ABC03
instance is a maximum outlier, given that it has much more aspects than the other
versions. This is expected since it has all the aspects that possess state, which cannot be
removed by ProGuard.
Nonetheless, our optimizations decreasing the overhead of AspectJ in MobileMedia
by 50% is a significant result, although we believe that with some refactorings in the
aspects to transform the state in inter-type declarations, this reduction could have been
even more effective.
Table 5.5 shows the number of applications of each optimization in each instance of
MobileMedia. We can see that with each number increase in the name of the A, B and
C instances the number of optimization applications increase. This is due to the fact
that the instances with the name ending in 02 have some optional features enabled, while
the ones ending in 03 have even more optional features enabled. The ABC03 instance,
which has all alternative and mandatory features, has the largest number of optimization
applications, as expected.
Unlike BestLap, we cannot determine the number of advices, initialized inter-type
5.2 MOBILEMEDIA 80
Instance Original AspectJ AspectJ (optimized)
A01 20,897 26,437 23,351
A02 22,117 30.000 26,454
A03 33,267 45,130 38,863
B01 23,707 30,084 27,016
B02 24,966 33,818 29,840
B03 25,961 36,781 32,077
C01 24,589 30,465 26,922
C02 25,845 33,769 30,023
C03 29,960 41,926 36,351
ABC03 47,025 70,090 59,930
Arithmetic Mean 27,833 37,850 33,083
Average mean size in-
crease in relation to
original
0% 34.54% 17.96%
Table 5.4 Comparison (in bytes) of the original version of MobileMedia against the aspects
version
fields and inter-type methods by the number of applications of the respective optimiza-
tions because some of them might not have been inlined, due to the fact that MobileMedia
has some aspects with state. This means that there were some aspect classfiles remaining
on the system after our optimizations were executed.
The size reduction in MobileMedia could not be as significant as the one in BestLap
due to the fact that some aspects had internal state, which prevented the inlining of
some advices and the application of some of our optimizations. Nonetheless, we obtained
a significant reduction in bytecode size for the MobileMedia SPL. Unlike BestLap, we
are not aware of which devices are the target of MobileMedia’s instances and cannot
assume that the AspectJ overhead without the optimizations renders any of the builds
uninstallable.
Now that we have seen that our optimizations reduce the size overhead in SPLs that
use AspectJ as a variation structuring mechanism, we present the results of performance
5.3 PERFORMANCE BENCHMARKS 81
Figure 5.4 Box plot of the original, hybrid and optimized versions of the MobileMedia SPL
benchmarks in the next section to ensure that the modifications made by our optimiza-
tions do not decrease the performance of AspectJ programs.
5.3 PERFORMANCE BENCHMARKS
We already saw that the optimizations we developed can significantly reduce the size of
SPLs that use AspectJ as variation structuring mechanism. However, we must ensure
that these optimizations do not degrade the performance of the applications. Therefore,
we applied our optimizations to a set of benchmark programs2 that have already been
used to test the performance of AspectJ optimizations [ACH+05b].
The decision to use predefined benchmarks was motivated by the fact that the ap-
plications used in the size analysis are interactive, which makes it hard to construct a
scenario that can be repeated with precision in order to collect execution time informa-
tion. Also, isolating pieces of code from them, to use individually as benchmark, would
also be a difficult task. Therefore, we chose to use predefined benchmarks.
2http://abc.comlab.ox.ac.uk/packages/ajbenches.zip
5.3 PERFORMANCE BENCHMARKS 82
Build ID Unnecessary
aspectOf()
Remover
Inter-type
Method Inliner
Inter-type Field
Initialization In-
liner
Accessor
Inliner
A01 24 3 1 4
A02 36 7 3 16
A03 50 22 10 20
B01 22 4 4 4
B02 36 10 6 16
B03 38 12 6 16
C01 22 4 4 6
C02 32 10 6 18
C03 33 17 7 34
ABC03 83 47 16 45
Table 5.5 Number of optimizations applications in the AspectJ version of MobileMedia
This benchmarks package has several programs used to benchmark AspectJ optimiza-
tions. We selected two programs to benchmark our optimizations, refered to as ants, an
aspect-oriented simulation of an ants colony written by one of the authors of that paper,
and a discrete event simulator for certificate revocation simulation [Arn], refered to as
sim.
The original build system of the benchmarks was modfied to add an option to com-
pile with abc using the inlining options and another with the inlining options and our
optimizations, and made these changes available3.
We selected these two benchmarks out of the many benchmarks available in package
because they were the ones with the largest number of applications of our optimizations.
Some of the programs did not have our optimizations modify the code at all, due to advice
accessing aspect state, for instance, while others had very few applications. Therefore,
we excluded programs that had none or very few applications of our optimizations.
The only optimization not applied to any of the benchmarks available was the accessor
inliner. As we can see in Table 5.6, the ants benchmark had applications of all of the other
3http://www.cin.ufpe.br/˜fhcl/msc/ajbenches.zip
5.3 PERFORMANCE BENCHMARKS 83
three optimizations, while the sim benchmark only had applications of the unnecessary
aspectOf() remover.
Optimization ants sim
Unnecessary aspectOf() remover 73 25
Inter-type field initialization inliner 2 0
Inter-type method inliner 6 0
Accessor inliner 0 0
Table 5.6 Applications of the optimizations in the benchmark programs
All benchmarks were run on a Intel Core 2 Duo E6550 2.33GHz with 2GB RAM
DDR2, Windows 7, using JDK version 1.6.0 16 and abc 1.2.1. We executed each op-
timization 102 times and discarded the first 2 execution times in order to remove the
interference of having their code loaded from hard drive during the first executions, which
can significantly affect the execution time.
Table 5.7 shows the arithmetic mean execution time and the standard deviation for
both benchmarks. For the ants benchmark we give results for the default abc compilation
that was in the benchmark prior to our modifications of the build system, for abc with
the inlining options and for abc with the inlining options and our optimizations. We can
see that the version with our optimizations is slightly faster, on average. However, with
these standard deviation values, the difference in execution time of the three versions is
not statistically significant.
For the sim benchmark we give the results for the pure Java version of the program,
and for the AspectJ version with the default abc compilation, with abc using the inlining
options and with abc using the inlining options and our optimizations. We can see that
the Java version is, on average, much faster than the AspectJ version with any of the
compilations available. The difference in execution time from the Java and AspectJ
versions is statistically significant.
This difference in execution time between the pure Java version and the AspectJ
versions is due to the fact that the advice used in the AspectJ version to enforce the null-
check uses the thisJoinPoint object to retrieve information about where the advice was
called, in order to print this information. This is considerably costlier than how the Java
5.3 PERFORMANCE BENCHMARKS 84
version prints the same information, which is by having a static method in class that
recieves the name of the class, method and line from where it was called, which are all
statically defined in the Java classes, while the AspectJ version uses thisJoinPoint to
determine those at run time.
Although the version compiled with our optimizations is faster, on average, than the
other abc compilations, the difference in execution time among the AspectJ versions is
not statistically significant.
Benchmark Arithmetic Mean Execution Time (s) Standard Deviation
ants abc 8,572 0,064
ants abc-inline 8,618 0,062
ants abc-optimized 8,499 0,083
nullptr-sim java 0,279 0,011
nullptr-sim abc 0,406 0,030
nullptr-sim abc-inlined 0,376 0,013
nullptr-sim abc-optimized 0,369 0,020
Table 5.7 Execution time for the benchmarks
These results show that our optimizations do not degrade the performance of these
benchmarks, which was expected, given that our optimizations make small modifications
that reduce the number of method calls and context switching for the AspectJ constructs
optimized.
However, these benchmarks may not be the optimal examples to show the benefits
of our optimizations, given that the aspects used in the benchmark programs have ad-
vices with high quantifications, a small amount of inter-type methods and fields, and no
accessor usage. Albeit, we believe that using benchmarks that were not tailored to our
optimizations is useful to show that our optimizations are not harmful to the performance
of regular AspectJ programs.
Despite not increasing the execution time performance, in a statistically significant
manner, we have shown that our optimizations can significantly reduce the compiled size
of AspectJ SPLs, which is an important accomplishment given the memory constrained
scenario of mobile applications development.
CHAPTER 6
CONCLUSION
“To absent friends, lost loves, old gods, and the season of mists; and
may each and every one of us always give the devil his due.”
—NEIL GAIMAN
This work presented four optimizations designed to decrease the bytecode size of
Software Product Lines that use aspects to structure code variations. These optimizations
were made possible by the study we realized on the code generation of the two main
AspectJ compilers, ajc and abc. We presented the reasons behind the bytecode size
overhead created by both compilers for a subset of AspectJ constructs, which were used
to structure variations in Software Product Lines.
Our analysis identified abc as the compiler that generated the smallest bytecode when
aspects were used for structuring variations. The analysis also identified where each
compiler could be optimized for the generation of a more compact code. Based on the
results from the analysis, our four optimizations were designed and implemented for the
abc compiler.
We applied these optimizations to two Java ME Software Product Lines: BestLap
and MobileMedia. On BestLap product line we achieved a complete elimination of the
AspectJ overhead, and on MobileMedia the overhead was reduced by approximately 50%.
The result obtained for BestLap was better than MobileMedia due the fact that,
unlike BestLap, MobileMedia has aspects with internal state. Advices and inter-type
methods that access this state cannot be inlined, which is a precondition of some of our
optimizations. However, we analyzed MobileMedia’s aspects and found that their state
could have been inter-type declarations, which would allow a greater reduction of the
overhead with simple refactorings.
The bytecode size reduction we achieved is a significant step towards making AspectJ
a viable code variation structuring mechanism in Java ME Software Product Lines, re-
85
6.1 RELATED WORK 86
placing conditional compilation when possible. We also presented benchmarks that show
that our optimizations do not decrease execution time performance.
This work shows that simple optimizations may lead to a gain that may be a decisive
factor for choosing AspectJ as a mechanism for structuring code variations in Java ME
SPLs, and possibly in other types of SPLs. We gratefully acknowledge Meantime Mobile
Creations for sharing the source code of their games with us, allowing this work to be
realized.
6.1 RELATED WORK
The investigation described in this dissertation is mainly related to AspectJ in Software
Product Lines and AspectJ optimizations.
6.1.1 AspectJ in Software Product Lines
Vander Alves [Alv07] reviewed techniques for handling variability in Software Product
Lines, presented a framework for describing these techniques and compared them acord-
ing to the framework. The techniques reviwed were object-orientation and polymorphism,
object-oriented design paterns, frameworks, feature-oriented programming, deployment-
time and run-time variability, program transformation, conditional compilation and AOP.
His framework consisted of several items to describe the techniques, such as granularity,
binding time, reusability, performance, application size, among others. Conditional com-
pilation had positive values in granularity, supporting fine-grained and coarse-grained
variabilities, performance, support for structure and behavior variability and application
size. However, it presented low reusability, has no support for modular implementation
of crosscutting concerns and low legibility. AOP was found to also support fine-grained
and coarse grained granularities, however it is not as good in fine-grained variabilities
as conditional compilation. It also supports structure and behavior variability, supports
modular implementation of crosscutting concerns, and presents high legibility and low to
medium reusability. AOP’s performance varies on the binding time used, ranging from
low to high, and application size was found to grow considerably. His work also defined
methods for implementing extractive and reactive [Kru01] SPL adoption strategies, ex-
tented the notion of refactorings to SPLs and evaluates the proposed methods in two case
6.1 RELATED WORK 87
studies.
Pedro Matos [Jun08] presented a comparative analysis of variability implementation
techniques for source code artifacts in Software Product Lines. He defined a set of cri-
teria for comparing each technique: complexity of implementation artifacts, modularity,
separation of concerns and size overhead, which were evaluated using several metrics,
both existing and newly defined. He also proposed variability implementation patterns,
which define how each technique is applied to implement a specific type of source code
variation. The SPL used in his work was also BestLap and the variability implemen-
tation techniques analyzed were conditional compilation, inheritance, mixins and AOP.
Conditional compilation outperformed all others with regard to the bytecode size metric,
however, it fell short in modularity and separation of concerns metrics.
6.1.2 AspectJ Optimizations
Sascha Kuzins [Kuz04] presented optimizations for the around advice. He explains the
entire weaving process of abc and implements a number of optimizations for enhancing
the code generation of around advices. He presents two ways to avoid closures, the first
consisting of having the class in which the shadow (a compiler-generated method that
contains the join point captured) resides implement the closure interface, which avoids
the necessity of creating a new object to implement it. Having the class implement the
closure interface is a problem when there are multiple shadows in the same class, which he
solved by creating a Shadow-ID, an integer constant that uniquely identifies each shadow
application applying the same advice method to the same class. This constant can be
passed to the proceed invocation at each shadow and a switch block selects which code
to execute.
The other way of avoiding closures makes closure interfaces unnecessary by making
the shadow method static. All shadows of a specific advice are contained in a method
that uses an unique identifier called Static Class ID, combined with the Shadow-ID, to
uniquely identify from which class and from which shadow the call was made. An analysis
is also performed to determine whether a type could possibly be converted to the target
type at runtime, which can lead to removal of residues (runtime checks that verify if
the join point satisfies the conditions of the pointcut) at sites where they would never
6.1 RELATED WORK 88
succeed. These optimizations lead to code that could outperform ajc by up to 200%.
Avgustinov et al [ACH+05b] presented a novel implementation of the around advice,
which avoids closures in all but pathological cases, while not requiring inlining to avoid
code bloat. However, they note that inlining is a good optimization in certain situations,
but raise their concerns that duplicating the advice method for every advice application
may lead to code bloat. This is a valid concern for advices with high quantification,
which is not the case of the product lines analyzed in our work, where there is little or
no quantification.
Their work also presents a number of intraprocedural optimizations and analysis to
reduce and, sometimes, completely eliminate the overhead associated with the use of
the cflow pointcut, which is a pointcut used to intercept method calls in the dynamic
scope of others. Finally, they present reweaving as a novel methodology for defining new
program analysis and transformations in aspect-oriented languages.
Eduarco Cordeiro [Cor07] presented a study of weaving techniques in abc and ajc and
developed optimizations to improve code generation. He identified the problem of advice
and shadow repetition, which occurs when a class C has n shadows of an around advice
a, which results in the creation of n pairs of (advice, shadow) methods. His solution
removes the unncessary n-1 pairs and replaces references to these with the corresponding
method left in the code.
The other problem identified and optimized is the one of repeated context variables
in around advices. For shadows captured by around advice to execute correctly, the
context variables must be exposed, even if the programmer did explicitly not do so. The
problem arises when the programmer explicitly exposes the context variables, with the
this, target and args pointcuts, which are not reused from the ones already captured
implicitly. Optimizations for both problems were implemented in ajc and abc and showed
a decrease in code size and execution time.
Bodden et al [BCR09] analyzed the use of history-based advices, which are used for
runtime monitoring and conditional execution, based on the observed execution history.
They extended the AspectJ language with new constructs that can annotate advices with
relevant information from the domain knowledge. These annotations are used in a whole-
program analysis that removes advice-dispatch code from program locations at which an
advice’s dependencies cannot be fulfilled. Their work does not optimize the pure AspectJ
6.2 LIMITATIONS 89
language, but extend it, enabling the development of optimizations that take advantage
of the informations provided with the new constructs. They lowered the overhead of
history-based aspects, and, in some cases, completely eliminated it.
6.2 LIMITATIONS
Our optimizations have the limitation of relying on abc’s naming conventions in order
to identify which methods match the signature of compiler generated methods that are
subject to some of our optimizations. Though it should be uncommon to encounter false
positives on our signature checks, the possibility still exists.
Also, some of our optimizations are only applied when advices have been inlined.
However, inlining is not desirable in cases of advices with high quantification. We used
abc’s options to force advice inlining, but the optimal use of inlining would be one that
takes into account whether the aspect could be removed from the build if its advices
were inlined, the number of applications of the advice, and calculates whether inlining
increases or decreases the final size.
6.3 FUTURE WORK
Although we have evaluated our optimizations using two SPLs in the mobile applications
domain, we believe that our work may also be useful in other contexts. Therefore, it
would be interesting to evaluate our optimizations using SPLs from other contexts, such
as desktop or server applications, and even traditional AspectJ applications, to see how
much they would benefit from the application of our optimizations.
We have analyzed a subset of AspectJ constructs to identify if and why they generate
overhead. An interesting future work is extending this analysis to the entire AspectJ
language, while also analyzing more elaborate uses of these constructs.
Another possible future work is to implement our optimizations in ajc. Finally, we
could also reimplement the optimizations for abc in an earlier stage of the compilation
process, where there is more syntatic information, from abstract syntatic trees, that
would enable the optimizations to rely less on naming conventions and more on syntatic
information directly from the source code.
BIBLIOGRAPHY
[ACH+04] Pavel Avgustinov, Aske Simon Christensen, Laurie Hendren, Sascha Kuzins,
Jennifer Lhotak, Ondrej Lhotak, Oege de Moor, Damien Sereni, Ganesh
Sittampalam, and Julian Tibble. Building the abc aspectj compiler with
polyglot and soot. Technical report, The abc Group, October 2004.
[ACH+05a] Pael Avgustinov, Aske Simon Christensen, Laurie Hendren, Sascha Kuzins,
Jennifer Lhotak, Ondrej Lhotak, Oege de Moor, Damien Sereni, Ganesh Sit-
tampalam, and Julian Tibble. abc: An extensible aspectj compiler. TAOSD,
2005.
[ACH+05b] Pavel Avgustinov, Aske Simon Christensen, Laurie Hendren, Sascha Kuzins,
Jennifer Lhotak, Ondrej Lhotak, Oege de Moor, Damien Sereni, Ganesh
Sittampalam, and Julian Tibble. Optimising aspectj. PLDI, 2005.
[ACV+05] Vander Alves, Ivan Cardim, Heitor Vital, Pedro Sampaio, Alexandre Dam-
asceno, Paulo Borba, and Geber Ramalho. Comparative analysis of porting
strategies in j2me games. Proceedings of the 21st IEEE International Confer-
ence on Software Maintenance (ICSM’05), pages 123–132, September 2005.
[Alv07] Vander Alves. Implementing software product line adoption strategies. PhD
in informatics, Universidade Federal de Pernambuco, 2007.
[ANS+06] Vander Alves, Albeto Costa Neto, Sergio Soares, Gustavo Santos, Fernando
Calheiros, Vilmar Nepomuceno, Davi Pires, Jorge Leal, and Paulo Borba.
From conditional compilation to aspects: A case study in software product
lines migration. 1st Workshop on Aspect-Oriented Product Line Engineer-
ing, in conjunction with 5th ACM International Conference on Generative
Programming and Component Engineering, October 2006.
90
BIBLIOGRAPHY 91
[Arn] Andre Arnes. PKI certificate revocation. Available at
http://www.pvv.ntnu.no/ andrearn/certrev/.
[BCR09] Eric Bodden, Feng Chen, and Grigore Rosu. Dependent advice: A general
approach to optimizing history-based aspects. AOSD, 2009.
[CBS+07] Fernando Calheiros, Paulo Borba, Sergio Soares, Vilmar Nepomuceno, and
Vander Alves. Product line variability refactoring tool. 1st Workshop on
Refactoring Tools (WRT07), in conjunction with the 21st European Confer-
ence on Object-Oriented Programming, pages 33,34, July 2007.
[CLG+06] Tarcisio Camara, Rodrigo Lima, Rangner Guimaraes, Alexandre Damas-
ceno, Vander Alves, Pedro Macedo, and Geber Ramalho. Massive mobile
games porting: Meantime study case. Brazilian Symposium on Computer
Games and Digital Entertainment - Computing track, 2006.
[CN02] Paul Clements and Linda Northrop. Software Product Lines: Practices and
Patterns. Addison-Wesley, 2002.
[Col05] Leonardo Cole. Deriving refactorings for aspectj. Master’s thesis, Infor-
matics Center, Federal Universisty of Pernambuco, Recife, Brazil, February
2005.
[Cor07] Eduardo Santos Cordeiro. Otimizacoes na compilacao de adendos de con-
torno em programas orientados por aspectos. Master’s thesis, Universidade
Federal de Minas Gerais, 2007.
[FBB+99] Martin Fowler, Kent Beck, John Brant, William Opdyke, and Don Roberts.
Refactoring: Improving the Design of Existing Code. Addison-Wesley, 1999.
[FF00] Robert E. Filman and Daniel P. Friedman. Aspect-oriented programming is
quantification and obliviousness. pages 21–35. Addison-Wesley, 2000.
[HH04] Erik Hilsdale and Jim Hugunin. Advice weaving in aspectj. AOSD, 2004.
[Jun08] Pedro Osandy Alves Matos Junior. Analysis of techniques for implementing
variabilities in software product lines. Master’s thesis, Informatics Center,
Federal Universisty of Pernambuco, Recife, Brazil, February 2008.
BIBLIOGRAPHY 92
[KHH+01] Gregor Kiczales, Erik Hilsdale, Jim Hugunin, Mik Kersten, Jeffrey Palm,
and William G. Griswold. An overview of aspectj. ECOOP, 2001.
[KLM+97] Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda,
Cristina Videira Lopes, Jean-Marc Loingtier, and John Irwin. Aspect-
oriented programming. ECOOP, 1997.
[Kru01] Charles Krueger. Easing the transition to software mass customization. In
Proceedings of the 4th International Workshop on Software Product-Family
Engineering., pages 282–293, Bilbao, Spain, October 2001.
[KS94] M. Krone and G. Snelting. On the inference of configuration structures
from source code. Proceedings of the International Conference on Software
Engineering (ICSE), pages 49–57, 1994.
[Kuz04] Sascha Kuzins. Efficient implementation of around-advice for the aspect-
bench compiler. Master’s thesis, Oxford University, 2004.
[LY99] Tim Lindholm and Frank Yellin. The Java Virtual Machine
Specification. Addison-Wesley Professional, second edition, 1999.
http://java.sun.com/docs/books/vmspec/index.html.
[PBvdL05a] K. Pohl, G. Boockle, and F. J. van der Linden. Software Product Line
Engineering: Foundations, Principles and Techniques. Springer, 2005.
[PBvdL05b] K. Pohl, G. Boockle, and F. J. van der Linden. Software Product Lines:
Practices and Patterns. Springer-Verlag, 2005.
[Pro07] ProGuard. ProGuard, java class file shrinker, optimizer and obfuscator,
2007. http://proguard.sourceforge.net.
[SC92] H. Spencer and G. Collyer. #ifdef considered harmful or portability experi-
ence with c news. Proceedings of USENIX Conf, pages 185–198, 1992.
[S.M97] Steven S.Muchnick. Advanced Compiler Design and Implementation. Mor-
gan Kaufmann, 1997.
BIBLIOGRAPHY 93
[Smi88] J. E. Smith. Characterizing computer performance with a single number.
Commun. ACM, 31:1202–1206, October 1988.
[vdLSR07] F. J. van der Linden, K. Schmid, and E. Rommes. Software Product Lines in
Action: the Best Industrial Practice in Product Line Engineering. Springer,
2007.
[VRGH+00] Raja Vallee-Rai, Etienne Gagnon, Laurie J. Hendren, Patrick Lam, Patrice
Pominville, and Vijay Sundaresan. Optimizing java bytecode using the soot
framework: Is it feasible? Compiler Construction, pages 18–34, 2000.
[VRH98] Raja Vallee-Rai and Laurie J. Hendren. Jimple: Simplifying java bytecode
for analyses and transformations. Technical report, McGill University, July
1998.
[VRHS+99] Raja Vallee-Rai, Laurie Hendren, Vijay Sundaresan, Patrick Lam, Etienne
Gagnon, and Phong Co. Soot - a java optimization framework. Proceedings
of CASCON, pages 125–135, July 1999.
Top Related