Initial revision

bcel
jzigman 18 years ago
commit 7cd141f28e
  1. 504
      lgpl.license.txt
  2. 65
      src/edu/purdue/cs/bloat/Makefile
  3. 442
      src/edu/purdue/cs/bloat/cfg/Block.java
  4. 172
      src/edu/purdue/cs/bloat/cfg/DominanceFrontier.java
  5. 399
      src/edu/purdue/cs/bloat/cfg/DominatorTree.java
  6. 3688
      src/edu/purdue/cs/bloat/cfg/FlowGraph.java
  7. 97
      src/edu/purdue/cs/bloat/cfg/Handler.java
  8. 31
      src/edu/purdue/cs/bloat/cfg/Makefile
  9. 194
      src/edu/purdue/cs/bloat/cfg/ReplaceTarget.java
  10. 296
      src/edu/purdue/cs/bloat/cfg/Subroutine.java
  11. 445
      src/edu/purdue/cs/bloat/cfg/VerifyCFG.java
  12. 14
      src/edu/purdue/cs/bloat/cfg/package.html
  13. 47
      src/edu/purdue/cs/bloat/class.mk
  14. 2735
      src/edu/purdue/cs/bloat/codegen/CodeGenerator.java
  15. 823
      src/edu/purdue/cs/bloat/codegen/Liveness.java
  16. 27
      src/edu/purdue/cs/bloat/codegen/Makefile
  17. 752
      src/edu/purdue/cs/bloat/codegen/RegisterAllocator.java
  18. 9
      src/edu/purdue/cs/bloat/codegen/package.html
  19. 295
      src/edu/purdue/cs/bloat/context/BloatContext.java
  20. 26
      src/edu/purdue/cs/bloat/context/Makefile
  21. 483
      src/edu/purdue/cs/bloat/context/PersistentBloatContext.java
  22. 17
      src/edu/purdue/cs/bloat/context/package.html
  23. 537
      src/edu/purdue/cs/bloat/diva/InductionVarAnalyzer.java
  24. 25
      src/edu/purdue/cs/bloat/diva/Makefile
  25. 8
      src/edu/purdue/cs/bloat/diva/package.html
  26. 1281
      src/edu/purdue/cs/bloat/editor/ClassHierarchy.java
  27. 179
      src/edu/purdue/cs/bloat/editor/EditorContext.java
  28. 480
      src/edu/purdue/cs/bloat/editor/InstructionAdapter.java
  29. 70
      src/edu/purdue/cs/bloat/editor/InstructionVisitor.java
  30. 31
      src/edu/purdue/cs/bloat/editor/Makefile
  31. 143
      src/edu/purdue/cs/bloat/editor/MemberRef.java
  32. 117
      src/edu/purdue/cs/bloat/editor/MethodRef.java
  33. 112
      src/edu/purdue/cs/bloat/editor/NameAndType.java
  34. 10
      src/edu/purdue/cs/bloat/editor/package.html
  35. 853
      src/edu/purdue/cs/bloat/inline/CallGraph.java
  36. 730
      src/edu/purdue/cs/bloat/inline/Inline.java
  37. 122
      src/edu/purdue/cs/bloat/inline/InlineContext.java
  38. 152
      src/edu/purdue/cs/bloat/inline/InlineStats.java
  39. 30
      src/edu/purdue/cs/bloat/inline/Makefile
  40. 246
      src/edu/purdue/cs/bloat/inline/StackHeightCounter.java
  41. 19
      src/edu/purdue/cs/bloat/inline/package.html
  42. 126
      src/edu/purdue/cs/bloat/optimize/CodeGen.java
  43. 70
      src/edu/purdue/cs/bloat/optimize/ConstantPoolSizePrinter.java
  44. 921
      src/edu/purdue/cs/bloat/optimize/Main.java
  45. 31
      src/edu/purdue/cs/bloat/optimize/Makefile
  46. 243
      src/edu/purdue/cs/bloat/optimize/MethodBloater.java
  47. 140
      src/edu/purdue/cs/bloat/optimize/MethodState.java
  48. 90
      src/edu/purdue/cs/bloat/optimize/Optimization.java
  49. 7
      src/edu/purdue/cs/bloat/optimize/package.html
  50. 50
      src/edu/purdue/cs/bloat/reflect/ClassFormatException.java
  51. 25
      src/edu/purdue/cs/bloat/reflect/Makefile
  52. 14
      src/edu/purdue/cs/bloat/reflect/package.html
  53. 52
      src/edu/purdue/cs/bloat/ssa/ComponentVisitor.java
  54. 29
      src/edu/purdue/cs/bloat/ssa/Makefile
  55. 162
      src/edu/purdue/cs/bloat/ssa/PhiReturnStmt.java
  56. 594
      src/edu/purdue/cs/bloat/ssa/SSA.java
  57. 296
      src/edu/purdue/cs/bloat/ssa/SSAConstructionInfo.java
  58. 731
      src/edu/purdue/cs/bloat/ssa/SSAGraph.java
  59. 12
      src/edu/purdue/cs/bloat/ssa/package.html
  60. 26
      src/edu/purdue/cs/bloat/tbaa/Makefile
  61. 296
      src/edu/purdue/cs/bloat/tbaa/TBAA.java
  62. 829
      src/edu/purdue/cs/bloat/tbaa/TypeInference.java
  63. 12
      src/edu/purdue/cs/bloat/tbaa/package.html
  64. 19
      src/edu/purdue/cs/bloat/tests/BloatTester1.java
  65. 23
      src/edu/purdue/cs/bloat/tests/BloatTester2.java
  66. 25
      src/edu/purdue/cs/bloat/tests/BloatTester3.java
  67. 28
      src/edu/purdue/cs/bloat/tests/Makefile
  68. 712
      src/edu/purdue/cs/bloat/trans/DeadCodeElimination.java
  69. 301
      src/edu/purdue/cs/bloat/trans/ExprPropagation.java
  70. 36
      src/edu/purdue/cs/bloat/trans/Makefile
  71. 594
      src/edu/purdue/cs/bloat/trans/NodeComparator.java
  72. 978
      src/edu/purdue/cs/bloat/trans/Peephole.java
  73. 3882
      src/edu/purdue/cs/bloat/trans/SSAPRE.java
  74. 359
      src/edu/purdue/cs/bloat/trans/SideEffectChecker.java
  75. 327
      src/edu/purdue/cs/bloat/trans/StackOpt.java
  76. 76
      src/edu/purdue/cs/bloat/trans/StackOptimization.java
  77. 2014
      src/edu/purdue/cs/bloat/trans/ValueFolder.java
  78. 306
      src/edu/purdue/cs/bloat/trans/ValueFolding.java
  79. 536
      src/edu/purdue/cs/bloat/trans/ValueNumbering.java
  80. 45
      src/edu/purdue/cs/bloat/trans/package.html
  81. 82
      src/edu/purdue/cs/bloat/tree/AddressStoreStmt.java
  82. 146
      src/edu/purdue/cs/bloat/tree/ArithExpr.java
  83. 95
      src/edu/purdue/cs/bloat/tree/ArrayLengthExpr.java
  84. 116
      src/edu/purdue/cs/bloat/tree/ArrayRefExpr.java
  85. 454
      src/edu/purdue/cs/bloat/tree/AscendVisitor.java
  86. 56
      src/edu/purdue/cs/bloat/tree/Assign.java
  87. 89
      src/edu/purdue/cs/bloat/tree/CallExpr.java
  88. 141
      src/edu/purdue/cs/bloat/tree/CallMethodExpr.java
  89. 106
      src/edu/purdue/cs/bloat/tree/CallStaticExpr.java
  90. 116
      src/edu/purdue/cs/bloat/tree/CastExpr.java
  91. 104
      src/edu/purdue/cs/bloat/tree/CatchExpr.java
  92. 96
      src/edu/purdue/cs/bloat/tree/CheckExpr.java
  93. 60
      src/edu/purdue/cs/bloat/tree/CondExpr.java
  94. 127
      src/edu/purdue/cs/bloat/tree/ConstantExpr.java
  95. 136
      src/edu/purdue/cs/bloat/tree/DefExpr.java
  96. 60
      src/edu/purdue/cs/bloat/tree/DefInformation.java
  97. 452
      src/edu/purdue/cs/bloat/tree/DescendVisitor.java
  98. 65
      src/edu/purdue/cs/bloat/tree/EliminationInformation.java
  99. 246
      src/edu/purdue/cs/bloat/tree/Expr.java
  100. 76
      src/edu/purdue/cs/bloat/tree/ExprStmt.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

@ -0,0 +1,65 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
SUBDIRS = cfg \
codegen \
context \
diva \
editor \
inline \
main \
optimize \
reflect \
ssa \
tbaa \
tests \
trans \
tree \
util \
all:
@for i in $(SUBDIRS) ""; do \
if [ "x$$i" != "x" ]; then \
$(MAKE) -C $$i all; \
fi; \
done
clean:
@for i in $(SUBDIRS) ""; do \
if [ "x$$i" != "x" ]; then \
$(MAKE) -C $$i clean; \
fi; \
done
docs:
javadoc -d ../../../../../docs -sourcepath ../../../.. \
EDU.purdue.cs.bloat.util \
EDU.purdue.cs.bloat.reflect \
EDU.purdue.cs.bloat.editor \
EDU.purdue.cs.bloat.tree \
EDU.purdue.cs.bloat.cfg \
EDU.purdue.cs.bloat.ssa \
EDU.purdue.cs.bloat.tbaa \
EDU.purdue.cs.bloat.trans \
EDU.purdue.cs.bloat.diva \
EDU.purdue.cs.bloat.codegen \
EDU.purdue.cs.bloat.context \
EDU.purdue.cs.bloat.optimize \

@ -0,0 +1,442 @@
/*
* Class: Block
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.tree.StackOptimizationData;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.util.Assert;
import edu.purdue.cs.bloat.util.GraphNode;
import java.util.*;
/**
* <tt>Block</tt> represents a basic block of code used in control flow
* graphs. A basic block is always entered at its beginning and exits at its
* end. That is, its first statement is a label and its last statement is a
* jump. There are no other labels or jumps in between.
* <p>
* Each <tt>Block</tt> knows its parent block and its children in the
* dominator and postdominator trees. It also knows which blocks are in its
* dominance frontier and its postdominance frontier.
*
* @see FlowGraph
* @see DominatorTree
* @see DominanceFrontier
*/
public class Block extends GraphNode {
// There are several "types" of Blocks. A NON_HEADER block is not the
// header of a loop. An IRREDUCIBLE block is one of the headers of an
// irreducible loop. An irriducible loop has more than one entry
// point. They are very rare and are really ugly. The loop
// transformer tries to fix up multiple headers. A REDUCIBLE header is
// a header for a reducible loop.
public static final int NON_HEADER = 0;
public static final int IRREDUCIBLE = 1;
public static final int REDUCIBLE = 2;
FlowGraph graph; // CFG to which this Block belongs
InstructionHandle label; // This Block's Label
Tree tree; // Expression tree for this block
Block domParent; // Block that (immediately) dominates this Block
Block pdomParent;
Set domChildren; // Blocks that this Block dominates
Set pdomChildren; // The postdominator children of this block
Set domFrontier; // This Block's dominance frontier
Set pdomFrontier; // This Block's postdominace frontier
int blockType; // NON_HEADER, IRREDUCIBLE, or REDUCIBLE
Block header; // The block's loop header
StackOptimizationData stackOptimizer; // Stack Optimizer
/**
* Constructor.
*
* @param label
* The block's label. Labels are implemented with BCEL using
* InstructionHandle's attributes this means that a label
* instruction is also the first instruction in the block it
* labels.
* @param graph
* The CFG containing the block.
*/
Block(InstructionHandle label, FlowGraph graph) {
this.label = label;
this.graph = graph;
this.tree = null;
this.header = null;
this.blockType = NON_HEADER;
FlowGraph.setLabel(label); // Make sure it's set.
// A little unsure here the start of a Block should be the target of a
// BranchInstruction and hasTargeters() should be true.
domParent = null;
pdomParent = null;
domChildren = new LinkedHashSet();
pdomChildren = new LinkedHashSet();
domFrontier = new LinkedHashSet();
pdomFrontier = new LinkedHashSet();
stackOptimizer = new StackOptimizationData(this); // make
// StackOptimizationData
// object
}
/**
* Constructor.
*
* I use this method with caution the label should be set as soon as
* possible after constructing the block using setLabel().
*
* @param graph
* The CFG containing the block.
*/
Block(FlowGraph graph) {
this.graph = graph;
this.tree = null;
this.header = null;
this.blockType = NON_HEADER;
// A little unsure here the start of a Block should be the target of a
// BranchInstruction and hasTargeters() should be true, otherwise we may
// be able to set an attribute.
domParent = null;
pdomParent = null;
domChildren = new LinkedHashSet();
pdomChildren = new LinkedHashSet();
domFrontier = new LinkedHashSet();
pdomFrontier = new LinkedHashSet();
stackOptimizer = new StackOptimizationData(this); // make
// StackOptimizationData
// object
}
/**
* added so that I can delay adding labels until I have parsed the first
* instruction
*
* @param label
* The InstructionHandle of the first instruction in the block.
*/
public void setLabel(InstructionHandle label) {
FlowGraph.setLabel(label);
this.label = label;
}
/**
* Returns the stack optimizer for this block.
*
* @return The stack optimizer.
*/
public StackOptimizationData stackOptimizer() {
return stackOptimizer;
}
/**
* Returns the expression tree for this block.
*
* @return The tree.
*/
public Tree tree() {
return tree;
}
/**
* Sets the expression tree for this block.
*/
public void setTree(Tree tree) {
this.tree = tree;
}
/**
* Returns the CFG containing the block.
*
* @return The CFG.
*/
public FlowGraph graph() {
return graph;
}
/**
* Returns the label associated with this block.
*/
public InstructionHandle label() {
return label;
}
/**
* Visits the expression tree contained in this block.
*/
public void visitChildren(TreeVisitor visitor) {
if (tree != null) {
tree.visit(visitor);
}
}
public void visit(TreeVisitor visitor) {
visitor.visitBlock(this);
}
/**
* Sets the type of this Block. A Block may have one of three types:
*
* <ul>
* <li><tt>NON_HEADER</tt>: Not the header of any loop
* <li><tt>IRREDUCIBLE</tt>: Header of an irreducible loop
* <li><tt>REDUCIBLE</tt>: Header of a reducible loop
* </ul>
*
* A <i>loop</i> is a strongly connected component of a control flow graph.
* A loop's <i>header</i> is the block that dominates all other blocks in
* the loop. A loop is <i>reducible</i> if the only way to enter the loop
* is through the header.
*/
void setBlockType(int blockType) {
this.blockType = blockType;
if (FlowGraph.DEBUG) {
System.out.println(" Set block type " + this);
}
}
/**
* Returns the type of this Block.
*/
int blockType() {
return blockType;
}
public void setHeader(Block header) {
this.header = header;
if (FlowGraph.DEBUG) {
System.out.println(" Set header " + this);
}
}
public Block header() {
return header;
}
/**
* Returns a string representation of this block.
*/
public String toString() {
String s = "<block " + label + " hdr=";
if (header != null) {
s += header.label();
} else {
s += "null";
}
switch (blockType) {
case NON_HEADER:
break;
case IRREDUCIBLE:
s += " irred";
break;
case REDUCIBLE:
s += " red";
break;
}
if (this == graph.source()) {
return s + " source>";
} else if (this == graph.init()) {
return s + " init>";
} else if (this == graph.sink()) {
return s + " sink>";
} else {
return s + ">";
}
}
/**
* Returns the basic blocks that this Block immediately dominates. That is,
* it returns this Block's children in the dominator tree for the CFG.
*/
Collection domChildren() {
return domChildren;
}
/**
* Returns the immediate dominator of this Block. That is, it returns the
* Block's parent in the dominator tree, its immediate dominator.
*/
Block domParent() {
return domParent;
}
/**
* Specifies that Block dominates this Block (parent in the dominator tree,
* the immediate dominator).
*
* @param block
* Block that dominates this Block.
*/
void setDomParent(Block block) {
// If this Block already had a dominator specified, remove
// it from its dominator's children.
if (domParent != null) {
domParent.domChildren.remove(this);
}
domParent = block;
// Add this Block to its new dominator's children.
if (domParent != null) {
domParent.domChildren.add(this);
}
}
/**
* Returns whether or this Block dominates another given Block. A node X
* dominates a node Y when every path from the first node in the CFG (Enter)
* to Y must pass through X.
*/
public boolean dominates(Block block) {
Block p = block;
while (p != null) {
if (p == this) {
return true;
}
p = p.domParent();
}
return false;
}
/**
* Returns the children of this Block in the CFG's postdominator tree.
*/
Collection pdomChildren() {
return pdomChildren;
}
/**
* Returns the parent of this Block in the CFG's postdominator tree.
*/
Block pdomParent() {
return pdomParent;
}
/**
* Sets this Block's parent in the postdominator tree.
*/
void setPdomParent(Block block) {
if (pdomParent != null) {
pdomParent.pdomChildren.remove(this);
}
pdomParent = block;
if (pdomParent != null) {
pdomParent.pdomChildren.add(this);
}
}
/**
* Determines whether or not this block postdominates a given block. A block
* X is said to postdominate a block Y when every path from Y to the last
* node in the CFG (Exit) passes through X. This relationship can be thought
* of as the reverse of dominance. That is, X dominates Y in the reverse
* CFG.
*
* @see DominatorTree
*/
public boolean postdominates(Block block) {
Block p = block;
while (p != null) {
if (p == this) {
return true;
}
p = p.pdomParent();
}
return false;
}
/**
* Returns the blocks that are in this block's dominance frontier. The
* dominance frontier of a node X in a CFG is the set of all nodes Y such
* that X dominates a predacessor of Y, but does not strictly dominate Y.
* Nodes in the dominance frontier always have more than one parent (a
* join).
*
* @see DominanceFrontier
*/
Collection domFrontier() {
Assert.isTrue(domFrontier != null);
return domFrontier;
}
/**
* Returns the postdominance frontier for this node. A postdominace frontier
* is essentially the same as a dominace frontier, but the postdominance
* relationship is used instead of the dominance relationship.
*/
Collection pdomFrontier() {
Assert.isTrue(pdomFrontier != null);
return pdomFrontier;
}
}

@ -0,0 +1,172 @@
/*
* Class: DominanceFrontier
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import java.util.*;
/**
* <tt>DominanceFrontier</tt> is used to calculate the <i>dominance frontier</i>
* of each node in a control flow graph.
* <p>
* The <i>dominance frontier</i> of a node x is the set of all nodes w such
* that x dominates a predacessor of w, but does not strictly dominate w.
* Basically, nodes in the dominance frontier have one parent that <b>is</b>
* dominated by x and at least one parent that <b>is not</b> dominated by x.
* <p>
* <tt>DominanceFrontier</tt> can be used to calculate both the dominance
* (forward) and the postdominance (reverse) frontiers for a control flow graph.
*
* @see FlowGraph
*/
public class DominanceFrontier {
/**
* Calculates the dominance frontier for a cfg and notifies the blocks in it
* appropriately.
*
* @param graph
* The cfg to operate on
* @param reverse
* Do we calculate the postdominance frontier?
*/
public static void buildFrontier(FlowGraph graph, boolean reverse) {
if (!reverse) {
calcFrontier(graph.source(), graph, reverse);
} else {
calcFrontier(graph.sink(), graph, reverse);
}
}
/**
* Recursively traverses the cfg and builds up the dominance frontier.
* <p>
* A block n's dominance frontier is the union of two sets of nodes. The
* first set is the nodes in the dominance frontier of the nodes that n
* dominates that are not dominated by n's immediate dominator. The second
* set consists of the successors of n that are not strictly dominated by n.
*
* @param block
* The block to start from (either source or sink)
* @param graph
* The cfg from which to get blocks
* @param reverse
* Do we calculate the dominance or postdominance frontier?
*
* @return The blocks in the (post)dominance frontier of block
*/
private static LinkedList calcFrontier(Block block, FlowGraph graph,
boolean reverse) {
// local is an array of Blocks that are in block's dominance
// frontier. It is indexed by the block's pre-order index. I
// suppose an array is used so that no block is added to the
// dominance frontier twice.
Block[] local = new Block[graph.size()];
Iterator children; // The blocks that are dominated by block
if (!reverse) {
children = block.domChildren().iterator();
} else {
children = block.pdomChildren().iterator();
}
// Recursively calculate the nodes in the dominance frontier of
// block that are not dominated by block's immediate dominator
while (children.hasNext()) {
Block child = (Block) children.next();
LinkedList df = calcFrontier(child, graph, reverse);
Iterator e = df.iterator();
while (e.hasNext()) {
Block dfChild = (Block) e.next();
if (!reverse) {
if (block != dfChild.domParent())
local[graph.preOrderIndex(dfChild)] = dfChild;
} else {
if (block != dfChild.pdomParent())
local[graph.preOrderIndex(dfChild)] = dfChild;
}
}
}
Iterator succs = reverse ? graph.preds(block).iterator() : graph.succs(
block).iterator();
// Caculate the successors of block that are not strictly
// dominated by block.
while (succs.hasNext()) {
Block succ = (Block) succs.next();
// If block is not the immediate (post)dominator of its
// successor, add it to block's dominance frontier.
if (!reverse) {
if (block != succ.domParent())
local[graph.preOrderIndex(succ)] = succ;
} else {
if (block != succ.pdomParent())
local[graph.preOrderIndex(succ)] = succ;
}
}
LinkedList v = new LinkedList(); // The dominance frontier
for (int i = 0; i < local.length; i++) {
if (local[i] != null) {
v.add(local[i]);
}
}
// Set block's (post)dominance frontier
if (!reverse) {
block.domFrontier().clear();
block.domFrontier().addAll(v);
} else {
block.pdomFrontier().clear();
block.pdomFrontier().addAll(v);
}
return v;
}
}

@ -0,0 +1,399 @@
/*
* Class: DominatorTree
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import java.util.*;
import edu.purdue.cs.bloat.util.Assert;
/**
* DominatorTree finds the dominator tree of a FlowGraph.
* <p>
* The algorithm used is Purdum-Moore. It isn't as fast as Lengauer-Tarjan, but
* it's a lot simpler.
*
* @see FlowGraph
* @see Block
*/
public class DominatorTree {
public static boolean DEBUG = false;
/**
* Calculates what vertices dominate other verices and notify the basic
* Blocks as to who their dominator is.
*
* @param graph
* The cfg that is used to find the dominator tree.
* @param reverse
* Do we go in revsers? That is, are we computing the dominatance
* (false) or postdominance (true) tree.
* @see Block
*/
public static void buildTree(FlowGraph graph, boolean reverse) {
int size = graph.size(); // The number of vertices in the cfg
Map snkPreds = new LinkedHashMap(); // The predacessor vertices from the
// sink
// Determine the predacessors of the cfg's sink node
insertEdgesToSink(graph, snkPreds, reverse);
// Get the index of the root
int root = reverse ? graph.preOrderIndex(graph.sink()) : graph
.preOrderIndex(graph.source());
Assert.isTrue(0 <= root && root < size);
// Bit matrix indicating the dominators of each vertex.
// If bit j of dom[i] is set, then node j dominates node i.
BitSet[] dom = new BitSet[size];
// A bit vector of all 1's
BitSet ALL = new BitSet(size);
for (int i = 0; i < size; i++) {
ALL.set(i);
}
// Initially, all the bits in the dominance matrix are set, except
// for the root node. The root node is initialized to have itself
// as an immediate dominator.
//
for (int i = 0; i < size; i++) {
BitSet blockDoms = new BitSet(size);
dom[i] = blockDoms;
if (i != root) {
blockDoms.or(ALL);
} else {
blockDoms.set(root);
}
}
// Did the dominator bit vector array change?
boolean changed = true;
while (changed) {
changed = false;
// Get the basic blocks contained in the cfg
Iterator blocks = reverse ? graph.postOrder().iterator() : graph
.preOrder().iterator();
// Compute the dominators of each node in the cfg. We iterate
// over every node in the cfg. The dominators of a node, x, are
// found by taking the intersection of the dominator bit vectors
// of each predacessor of x and unioning that with x. This
// process is repeated until no changes are made to any
// dominator
// bit vector.
while (blocks.hasNext()) {
Block block = (Block) blocks.next();
int i = graph.preOrderIndex(block);
Assert.isTrue(0 <= i && i < size, "Unreachable block " + block);
// We already know the dominators of the root, keep looking
if (i == root) {
continue;
}
BitSet oldSet = dom[i];
BitSet blockDoms = new BitSet(size);
blockDoms.or(oldSet);
// blockDoms := intersection of dom(pred) for all pred(block).
Collection preds = reverse ? graph.succs(block) : graph
.preds(block);
Iterator e = preds.iterator();
// Find the intersection of the dominators of block's
// predacessors.
while (e.hasNext()) {
Block pred = (Block) e.next();
int j = graph.preOrderIndex(pred);
Assert.isTrue(j >= 0, "Unreachable block " + pred);
blockDoms.and(dom[j]);
}
// Don't forget to account for the sink node if block is a
// leaf node. Appearantly, there are not edges between
// leaf nodes and the sink node!
preds = (Collection) snkPreds.get(block);
if (preds != null) {
e = preds.iterator();
while (e.hasNext()) {
Block pred = (Block) e.next();
int j = graph.preOrderIndex(pred);
Assert.isTrue(j >= 0, "Unreachable block " + pred);
blockDoms.and(dom[j]);
}
}
// Include yourself in your dominators?!
blockDoms.set(i);
// If the set changed, set the changed bit.
if (!blockDoms.equals(oldSet)) {
changed = true;
dom[i] = blockDoms;
}
}
}
// Once we have the predacessor bit vectors all squared away, we can
// determine which vertices dominate which vertices.
Iterator blocks = graph.nodes().iterator();
// Initialize each block's (post)dominator parent and children
while (blocks.hasNext()) {
Block block = (Block) blocks.next();
if (!reverse) {
block.setDomParent(null);
block.domChildren().clear();
} else {
block.setPdomParent(null);
block.pdomChildren().clear();
}
}
blocks = graph.nodes().iterator();
// A block's immediate dominator is its closest dominator. So, we
// start with the dominators, dom(b), of a block, b. To find the
// imediate dominator of b, we remove all blocks from dom(b) that
// dominate any block in dom(b).
while (blocks.hasNext()) {
Block block = (Block) blocks.next();
int i = graph.preOrderIndex(block);
Assert.isTrue(0 <= i && i < size, "Unreachable block " + block);
if (i == root) {
if (!reverse) {
block.setDomParent(null);
} else {
block.setPdomParent(null);
}
} else {
// Find the immediate dominator
// idom := dom(block) - dom(dom(block)) - block
BitSet blockDoms = dom[i];
// print(graph, reverse, "dom set", i, blockDoms);
BitSet idom = new BitSet(size);
idom.or(blockDoms);
idom.clear(i);
for (int j = 0; j < size; j++) {
if (i != j && blockDoms.get(j)) {
BitSet domDomBlocks = dom[j];
// idom = idom - (domDomBlocks - {j})
BitSet b = new BitSet(size);
b.or(domDomBlocks);
b.xor(ALL);
b.set(j);
idom.and(b);
}
}
Block parent = null;
// A block should only have one immediate dominator.
for (int j = 0; j < size; j++) {
if (idom.get(j)) {
Block p = (Block) graph.preOrder().get(j);
Assert.isTrue(parent == null, block
+ " has more than one immediate dominator: "
+ parent + " and " + p);
parent = p;
}
}
Assert.isTrue(parent != null, block + " has 0 immediate "
+ (reverse ? "postdominators" : "dominators"));
if (!reverse) {
if (DEBUG) {
System.out.println(parent + " dominates " + block);
}
block.setDomParent(parent);
} else {
if (DEBUG) {
System.out.println(parent + " postdominates " + block);
}
block.setPdomParent(parent);
}
}
}
}
/**
* Determines which nodes are predacessors of a cfg's sink node. Creates a
* Map that maps the sink node to its predacessors (or the leaf nodes to the
* sink node, their predacessor, if we're going backwards).
*
* @param graph
* The cfg to operate on.
* @param preds
* A mapping from leaf nodes to their predacessors. The exact
* semantics depend on whether or not we are going forwards.
* @param reverse
* Are we computing the dominators or postdominators?
*/
private static void insertEdgesToSink(FlowGraph graph, Map preds,
boolean reverse) {
BitSet visited = new BitSet(); // see insertEdgesToSinkDFS
BitSet returned = new BitSet();
visited.set(graph.preOrderIndex(graph.source()));
insertEdgesToSinkDFS(graph, graph.source(), visited, returned, preds,
reverse);
}
/**
* This method determines which nodes are the predacessor of the sink node
* of a cfg. A depth-first traversal of the cfg is performed. When a leaf
* node (that is not the sink node) is encountered, add an entry to the
* preds Map.
*
* @param graph
* The cfg being operated on.
* @param block
* The basic Block to start at.
* @param visited
* Vertices that were visited
* @param returned
* Vertices that returned
* @param preds
* Maps a node to a HashSet representing its predacessors. In the
* case that we're determining the dominace tree, preds maps the
* sink node to its predacessors. In the case that we're
* determining the postdominance tree, preds maps the sink node's
* predacessors to the sink node.
* @param reverse
* Do we go in reverse?
*/
private static void insertEdgesToSinkDFS(FlowGraph graph, Block block,
BitSet visited, BitSet returned, Map preds, boolean reverse) {
boolean leaf = true; // Is a vertex a leaf node?
// Get the successors of block
Iterator e = graph.succs(block).iterator();
while (e.hasNext()) {
Block succ = (Block) e.next();
// Determine index of succ vertex in a pre-order traversal
int index = graph.preOrderIndex(succ);
Assert.isTrue(index >= 0, "Unreachable block " + succ);
if (!visited.get(index)) {
// If the successor block hasn't been visited, visit it
visited.set(index);
insertEdgesToSinkDFS(graph, succ, visited, returned, preds,
reverse);
returned.set(index);
leaf = false;
} else if (returned.get(index)) {
// Already visited and returned, so a descendent of succ
// has an edge to the sink.
leaf = false;
}
}
if (leaf && block != graph.sink()) {
// If we're dealing with a leaf node that is not the sink, set
// up its predacessor set.
if (!reverse) {
// If we're going forwards (computing dominators), get the
// predacessor vertices from the sink
Set p = (Set) preds.get(graph.sink());
// If there are no (known) predacessors, make a new
// LinkedHashSet to
// store them and register it in the pred Map.
if (p == null) {
p = new LinkedHashSet();
preds.put(graph.sink(), p);
}
// The block is in the predacessors of the sink
p.add(block);
} else {
// If we're going backwards, get the block's predacessors
Set p = (Set) preds.get(block);
if (p == null) {
p = new LinkedHashSet();
preds.put(block, p);
}
// Add the sink vertex to the predacessors of the block
p.add(graph.sink());
}
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,97 @@
/*
* Class: Handler
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import org.apache.bcel.generic.Type;
import java.util.*;
/**
* <tt>Handler</tt> represents a try-catch block. It containes a set of
* protected <tt>Block</tt>s (the "try" blocks), a catch <tt>Block</tt>,
* and the <tt>Type</tt> of exception that is caught by the catch block.
*
* @see Block
* @see edu.purdue.cs.bloat.reflect.Catch
* @see edu.purdue.cs.bloat.editor.TryCatch
*/
public class Handler {
Set protectedBlocks;
Block catchBlock;
final Type type;
/**
* Constructor.
*
* @param catchBlock
* The block of code that handles an exception
* @param type
* The type of exception that is thrown
*/
public Handler(Block catchBlock, Type type) {
this.protectedBlocks = new LinkedHashSet();
this.catchBlock = catchBlock;
this.type = type;
}
/**
* Returns a <tt>Collection</tt> of the "try" blocks.
*/
public Collection protectedBlocks() {
return protectedBlocks;
}
public void setCatchBlock(Block block) {
catchBlock = block;
}
public Block catchBlock() {
return catchBlock;
}
public Type catchType() {
return type;
}
public String toString() {
return "try -> catch (" + type + ") " + catchBlock;
}
}

@ -0,0 +1,31 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
Block.class\
DominanceFrontier.class\
DominatorTree.class\
FlowGraph.class\
ReplaceTarget.class\
Subroutine.class\
VerifyCFG.class
include ../class.mk

@ -0,0 +1,194 @@
/*
* Class: ReplaceTarget
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import java.util.*;
import edu.purdue.cs.bloat.tree.GotoStmt;
import edu.purdue.cs.bloat.tree.IfStmt;
import edu.purdue.cs.bloat.tree.JsrStmt;
import edu.purdue.cs.bloat.tree.JumpStmt;
import edu.purdue.cs.bloat.tree.RetStmt;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.SwitchStmt;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
/**
* <tt>ReplaceTarget</tt> replaces the block that is the target of a
* <tt>JumpStmt</tt>, <tt>JsrStmt</tt>, <tt>RetStmt</tt>,
* <tt>GotoStmt</tt>, <tt>SwitchStmt</tt>, or <tt>IfStmt</tt> with
* another <tt>Block</tt>.
*/
public class ReplaceTarget extends TreeVisitor {
Block oldDst;
Block newDst;
public ReplaceTarget(Block oldDst, Block newDst) {
this.oldDst = oldDst;
this.newDst = newDst;
}
public void visitTree(Tree tree) {
Stmt last = (Stmt) tree.lastStmt();
if (last instanceof JumpStmt) {
JumpStmt stmt = (JumpStmt) last;
if (FlowGraph.DEBUG) {
System.out.println(" Replacing " + oldDst + " with " + newDst
+ " in " + stmt);
}
if (stmt.catchTargets().remove(oldDst)) {
stmt.catchTargets().add(newDst);
}
stmt.visit(this);
}
}
public void visitJsrStmt(JsrStmt stmt) {
if (stmt.sub().entry() == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
stmt.block().graph().setSubEntry(stmt.sub(), newDst);
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
}
public void visitRetStmt(RetStmt stmt) {
Iterator paths = stmt.sub().paths().iterator();
while (paths.hasNext()) {
Block[] path = (Block[]) paths.next();
if (FlowGraph.DEBUG) {
System.out.println(" path = " + path[0] + " " + path[1]);
}
if (path[1] == oldDst) {
if (FlowGraph.DEBUG) {
System.out.println(" replacing ret to " + oldDst
+ " with ret to " + newDst);
}
path[1] = newDst;
((JsrStmt) path[0].tree().lastStmt()).setFollow(newDst);
}
}
}
public void visitGotoStmt(GotoStmt stmt) {
if (stmt.target() == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
stmt.setTarget(newDst);
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
}
public void visitSwitchStmt(SwitchStmt stmt) {
if (stmt.defaultTarget() == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
stmt.setDefaultTarget(newDst);
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
Block[] targets = stmt.targets();
for (int i = 0; i < targets.length; i++) {
if (targets[i] == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
targets[i] = newDst;
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
}
}
public void visitIfStmt(IfStmt stmt) {
if (stmt.trueTarget() == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
stmt.setTrueTarget(newDst);
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
if (stmt.falseTarget() == oldDst) {
if (FlowGraph.DEBUG) {
System.out.print(" replacing " + stmt);
}
stmt.setFalseTarget(newDst);
if (FlowGraph.DEBUG) {
System.out.println(" with " + stmt);
}
}
}
}

@ -0,0 +1,296 @@
/*
* Class: Subroutine
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.tree.AddressStoreStmt;
import edu.purdue.cs.bloat.tree.Tree;
import java.io.*;
import java.util.*;
/**
* Subroutine represents a subroutine (target of a <i>jsr</i> instruction) in
* java bytecode. Subroutines are used to implement the finally part of a
* try-catch-finally block.
* <p>
* Each Subroutine belongs in a control flow graph, has an entry and exit block,
* and has a local variable that contains its return address. Additionally, it
* maintains a list of paths from blocks in which the subroutine is called to
* block that is executed after the subroutine returns.
* <p>
* Note that it is assumed that each subroutine ends with a <i>ret</i>. While
* this is true for bytecode generated by javac, it is not required.
*
* @see AddressStoreStmt
* @see Block
*/
// Important: I assume there is a ret statement for each jsr.
// This is true for javac code, but not in general.
public class Subroutine {
FlowGraph graph; // CFG containing this Subroutine
Block entry; // Basic Block at beginning of code
Block exit; // Basic Block ending code
ArrayList paths;
ReturnaddressType returnAddress; // This Subroutine's return address
LocalVariableGen localVariable = null;
/**
* Constructor.
*
* @param graph
* The CFG containing the block.
*/
public Subroutine(FlowGraph graph) {
this.graph = graph;
this.entry = null;
this.exit = null;
this.paths = new ArrayList();
this.returnAddress = null;
}
/**
* Returns the local variable containing the return address of this
* subroutine.
*/
public ReturnaddressType returnAddress() {
return returnAddress;
}
/**
* Sets the address (stored in a LocalVariable) to which this subroutine
* will return once it is finished.
*
* @param returnAddress
* Local variable that stores the address to which the subroutine
* returns when it is completed.
*
* @see Tree#visit_astore
*/
public void setReturnAddress(ReturnaddressType returnAddress) {
this.returnAddress = returnAddress;
}
// Set and get Local variable that is used to store the return address
// instead of the stack
public LocalVariableGen localVariable() {
return localVariable;
}
public void setLocalVariable(LocalVariableGen localVar) {
this.localVariable = localVar;
}
public void unsetLocalVariable() {
this.localVariable = null;
}
/**
* Returns the number of places that this subroutine is called.
*/
public int numPaths() {
return paths.size();
}
/**
* Returns the paths (a Collection of two-element arrays of Blocks) that
* represent the Blocks that end in a call to this subroutine and the block
* that begin with the return address from this subroutine.
*/
public Collection paths() {
return paths;
}
/**
* Returns the CFG that contains this subroutine.
*/
public FlowGraph graph() {
return graph;
}
/**
* Removes all paths involving block regardless of whether it is a calling
* (source) block or a returning (target) block.
*/
public void removePathsContaining(Block block) {
for (int i = paths.size() - 1; i >= 0; i--) {
Block[] path = (Block[]) paths.get(i);
if (path[0] == block || path[1] == block) {
if (FlowGraph.DEBUG) {
System.out.println("removing path " + path[0] + " -> "
+ path[1]);
}
paths.remove(i);
}
}
}
/**
* Removes a path between a caller Block and a return Block.
*/
public void removePath(Block callerBlock, Block returnBlock) {
for (int i = 0; i < paths.size(); i++) {
Block[] path = (Block[]) paths.get(i);
if (path[0] == callerBlock && path[1] == returnBlock) {
if (FlowGraph.DEBUG) {
System.out.println("removing path " + path[0] + " -> "
+ path[1]);
}
paths.remove(i);
return;
}
}
}
/**
* Removes all caller-return paths.
*/
public void removeAllPaths() {
paths = new ArrayList();
}
/**
* Adds a path from the block before a Subroutine is called to a block after
* the subroutine is called. If the callerBlock is already associated with a
* returnBlock, the old returnBlock is replaced.
*
* @param callerBlock
* The block in which the subroutine is called. This Block ends
* with a <i>jsr</i> to this subroutine.
* @param returnBlock
* The block to which the subroutine returns. This Block begins
* at the return address of this subroutine.
*/
public void addPath(Block callerBlock, Block returnBlock) {
for (int i = 0; i < paths.size(); i++) {
Block[] path = (Block[]) paths.get(i);
if (path[0] == callerBlock) {
path[1] = returnBlock;
return;
}
}
paths.add(new Block[] { callerBlock, returnBlock });
}
/**
* Returns the "return block" for a given "caller block".
*/
public Block pathTarget(Block block) {
for (int i = 0; i < paths.size(); i++) {
Block[] path = (Block[]) paths.get(i);
if (path[0] == block) {
return path[1];
}
}
return null;
}
/**
* Returns the "caller block" for a given "return block".
*/
public Block pathSource(Block block) {
for (int i = 0; i < paths.size(); i++) {
Block[] path = (Block[]) paths.get(i);
if (path[1] == block) {
return path[0];
}
}
return null;
}
/**
* Sets the entry Block for this Subroutine.
*/
public void setEntry(Block entry) {
this.entry = entry;
}
/**
* Sets the exit Block for this Subroutine.
*/
public void setExit(Block exit) {
this.exit = exit;
}
/**
* Returns the first Block in the subroutine.
*/
public Block entry() {
return entry;
}
/**
* Returns the last Block in the subroutine.
*/
public Block exit() {
return exit;
}
/**
* Prints a textual representation of this Subroutine.
*
* @param out
* The PrintStream to which to print.
*/
public void print(PrintStream out) {
out.println(" " + entry);
Iterator e = paths().iterator();
while (e.hasNext()) {
Block[] path = (Block[]) e.next();
out.println(" path: " + path[0] + " -> " + path[1]);
}
}
public String toString() {
return "sub " + entry;
}
}

@ -0,0 +1,445 @@
/*
* Class: VerifyCFG
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.cfg;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.tree.DefExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.ExprStmt;
import edu.purdue.cs.bloat.tree.GotoStmt;
import edu.purdue.cs.bloat.tree.IfStmt;
import edu.purdue.cs.bloat.tree.JsrStmt;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.RetStmt;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.SwitchStmt;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
import java.util.*;
/**
* VerifyCFG visits the nodes in a control flow graph and verifies that certain
* properties of the graph are true. For instance, value numbers of expressions
* are not equal to -1, node connections are consistent, exception handlers are
* set up correctly, etc. Mostly used for debugging purposes.
*/
public class VerifyCFG extends TreeVisitor implements Optimization {
Block block; // The Block containing the node being visited
Node parent; // The (expected) parent of the node being visited
FlowGraph cfg; // The CFG being visited
Set uses; // Expressions in which a definition is used
Set nodes; // (Visited) nodes in the CFG
boolean checkValueNumbers; // Do we check the value numbers of expressions?
public void transform(MethodState state) {
state.controlFlowGraph().visit(this);
}
public String traceMessage(String dateString) {
return null;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
/**
* Constructor. Don't check value numbers.
*/
public VerifyCFG() {
this(false);
}
/**
* Constructor. Since value numbers are not strictly part of the control
* flow graph, they may or may not be checked. For instance, if a CFG is
* being verfied before value numbers are assigned, we would not want to
* check them.
*
* @param checkValueNumbers
* Are the value numbers of expressions checked?
*/
public VerifyCFG(boolean checkValueNumbers) {
this.checkValueNumbers = checkValueNumbers;
}
/**
* Verify the specified call flow graph. Does not check the value numbers.
*
* @param cfg
* The call flow graph to verify.
*/
public static void verify(FlowGraph cfg) {
cfg.visit(new VerifyCFG());
}
/**
* Visit the blocks and expression trees in a control flow graph. Examine
* the uses of a variable that is defined in the CFG. Make that all uses are
* reachable (i.e. are in the CFG).
*/
public void visitFlowGraph(FlowGraph cfg) {
if (FlowGraph.DEBUG) {
System.out.println("Verifying CFG for " + cfg.method());
}
this.cfg = cfg;
uses = new LinkedHashSet();
nodes = new LinkedHashSet();
cfg.visitChildren(this);
Iterator e = uses.iterator();
while (e.hasNext()) {
Expr use = (Expr) e.next();
Assert.isTrue(nodes.contains(use), "use = " + use + " ("
+ System.identityHashCode(use) + ") is not in the CFG");
}
if (FlowGraph.DEBUG) {
System.out.println("Verification successful");
}
this.cfg = null;
uses = null;
nodes = null;
block = null;
parent = null;
}
/**
* First make sure that the <tt>Block</tt> indeed is in the CFG. If the
* block begins an exception handler, then make sure that all edges from
* protected blocks lead to the handler block. Also make sure that all of
* the handler block's predacessor lead to protected blocks. Finally, make
* sure that the successor/predacessor relationship holds.
*/
public void visitBlock(Block block) {
Assert.isTrue(block.graph() == cfg, block + " is not in the CFG");
Iterator e;
Handler handler = (Handler) cfg.handlersMap().get(block);
// If this block is the first block in an exception handler, make
// sure that the only predacessor edges the block has are
// protected blocks that may throw the exception handled by the
// block. Additionally, we check that there are edges from all
// protected blocks to the handler block.
//
// The predacessor to the first block in an exception handler may
// be the init block. However, it is not really a protected
// block, so just overlook it.
if (handler != null) {
HashSet handlerPreds = new LinkedHashSet();
e = handler.protectedBlocks().iterator();
while (e.hasNext()) {
Block prot = (Block) e.next();
handlerPreds.add(prot);
handlerPreds.addAll(cfg.preds(prot));
}
HashSet extra = new LinkedHashSet(cfg.preds(block));
extra.removeAll(handlerPreds);
HashSet missing = new LinkedHashSet(handlerPreds);
missing.removeAll(cfg.preds(block));
Assert.isTrue((extra.size() == 0 && missing.size() == 0)
|| (missing.size() == 1 && missing.contains(cfg.init())),
"Handler prots = " + handlerPreds
+ " != handler block preds = " + cfg.preds(block)
+ " extra = " + extra + " missing = " + missing);
}
// Make sure that the predacessor has a successor and vice versa.
e = cfg.preds(block).iterator();
while (e.hasNext()) {
Block pred = (Block) e.next();
Assert.isTrue(cfg.succs(pred).contains(block), pred
+ " has no succ " + block);
Assert.isTrue(cfg.preds(block).contains(pred), block
+ " has no pred " + pred);
}
e = cfg.succs(block).iterator();
while (e.hasNext()) {
Block succ = (Block) e.next();
Assert.isTrue(cfg.succs(block).contains(succ), block
+ " has no succ " + succ);
Assert.isTrue(cfg.preds(succ).contains(block), succ
+ " has no pred " + block);
}
this.block = block;
parent = null;
block.visitChildren(this);
}
/**
* Make sure that all of targets of the <tt>ret</tt> are valid. The
* targets are the blocks to which the subroutine can return.
*/
public void visitRetStmt(RetStmt stmt) {
Set targets = new LinkedHashSet();
Iterator iter = stmt.sub().paths().iterator();
while (iter.hasNext()) {
Block[] path = (Block[]) iter.next();
targets.add(path[1]);
}
targets.addAll(stmt.catchTargets());
verifyTargets(stmt.block(), targets);
visitNode(stmt);
}
/**
* Make sure that all of the targets of the <tt>jsr</tt> are valid. The
* only target is the entry block of the subroutine.
*/
public void visitJsrStmt(JsrStmt stmt) {
Set targets = new LinkedHashSet();
targets.add(stmt.sub().entry());
targets.addAll(stmt.catchTargets());
verifyTargets(stmt.block(), targets);
visitNode(stmt);
}
/**
* Make sure that that all of the targets of the switch are valid.
*/
public void visitSwitchStmt(SwitchStmt stmt) {
Set targets = new LinkedHashSet();
targets.add(stmt.defaultTarget());
for (int i = 0; i < stmt.targets().length; i++) {
targets.add(stmt.targets()[i]);
}
targets.addAll(stmt.catchTargets());
verifyTargets(stmt.block(), targets);
visitNode(stmt);
}
/**
* Make sure that the targets of the if statement are valid. Targets consist
* of the true target, the false target, and the first blocks of any
* exceptions that may be thrown by the if statement.
*/
public void visitIfStmt(IfStmt stmt) {
Set targets = new LinkedHashSet();
targets.add(stmt.trueTarget());
targets.add(stmt.falseTarget());
targets.addAll(stmt.catchTargets());
verifyTargets(stmt.block(), targets);
visitNode(stmt);
}
/**
* Make sure that the target of <tt>goto</tt> is valid.
*/
public void visitGotoStmt(GotoStmt stmt) {
Set targets = new LinkedHashSet();
targets.add(stmt.target());
targets.addAll(stmt.catchTargets());
verifyTargets(stmt.block(), targets);
visitNode(stmt);
}
/**
* Verifies information about the targets of a jump in a given block. First,
* make sure that the number of targets is the same as the number of
* sucessor nodes to the block. Make sure that targets of all of the jumps
* are indeed in the CFG. Make sure that every target is a successor of the
* block.
*/
private void verifyTargets(Block block, Set targets) {
Assert.isTrue(targets.size() == cfg.succs(block).size(), block
+ " has succs " + cfg.succs(block) + " != " + targets + " in "
+ block.tree().lastStmt());
Iterator iter = targets.iterator();
while (iter.hasNext()) {
Block target = (Block) iter.next();
Assert.isTrue(block.graph().hasNode(target), target
+ " is not in the CFG");
Assert.isTrue(cfg.succs(block).contains(target), target
+ " is not a succ of " + block + " "
+ block.tree().lastStmt());
}
}
/**
* If desired, makes sure that the store expression's value number is not
* -1. Makes sure that the store expression's block and parent <tt>Node</tt>
* are what we expect them to be. If the type of the <tt>StoreExpr</tt> is
* void, then make sure that its parent is an <tt>ExprStmt</tt> (i.e. make
* sure it is not nested within another expression).
*/
public void visitStoreExpr(StoreExpr node) {
nodes.add(node);
if (checkValueNumbers) {
Assert.isTrue(node.valueNumber() != -1, node
+ ".valueNumber() = -1");
}
Assert.isTrue(node.block() == block, node + ".block() = "
+ node.block() + " != block = " + block);
Assert.isTrue(node.parent() == parent, node + ".parent() = "
+ node.parent() + " != parent = " + parent);
// Visit the MemExpr into which node stores.
parent = node;
node.target().visit(this);
// Visit the expression whose value is being stored by node
parent = node;
node.expr().visit(this);
parent = node.parent();
if (node.type().equals(Type.VOID)) {
Assert.isTrue(parent instanceof ExprStmt, "parent of " + node
+ " = " + parent + " is not an ExprStmt");
}
}
/**
* Make sure that the <tt>Node</tt> resides in the block that we expect it
* to and that it has the expected parent expression tree <tt>Node</tt>.
* Make sure that the children of this <tt>Node</tt> are also correct.
*/
public void visitNode(Node node) {
nodes.add(node);
Assert.isTrue(node.block() == block, node + ".block() = "
+ node.block() + " != block = " + block);
Assert.isTrue(node.parent() == parent, node + ".parent() = "
+ node.parent() + " != parent = " + parent);
final ArrayList children = new ArrayList();
node.visitChildren(new TreeVisitor() {
public void visitNode(Node n) {
children.add(n);
}
});
Iterator e = children.iterator();
while (e.hasNext()) {
Node child = (Node) e.next();
parent = node;
child.visit(this);
}
parent = node.parent();
}
/**
* If desired, make sure that the value number of the <tt>Expr</tt> is not
* -1.
*/
public void visitExpr(Expr expr) {
if (checkValueNumbers) {
Assert.isTrue(expr.valueNumber() != -1, expr
+ ".valueNumber() = -1");
}
visitNode(expr);
}
/**
* Keep track of all the uses of the expression defined by the
* <tt>DefExpr</tt>. This information is used when verifying the
* <tt>FlowGraph</tt>.
*/
public void visitDefExpr(DefExpr expr) {
uses.addAll(expr.uses());
visitExpr(expr);
}
/**
* Make sure that the <tt>VarExpr</tt> either defines a local variable, is
* defined by another expression, or is the child of a <tt>PhiStmt</tt>
* (therefore making the <tt>VarExpr</tt> a phi-variable).
*/
public void visitVarExpr(VarExpr expr) {
Assert.isTrue(expr.isDef() || expr.def() != null
|| expr.parent() instanceof PhiStmt, "Null def for variable "
+ expr);
visitDefExpr(expr);
}
}

@ -0,0 +1,14 @@
<html>
<body>
<p>Classes to represent a Java method as a control flow graph of basic
blocks. A <em>basic block</em> is a sequence of code that is entered
only in once place (e.g. the target of a branch statement) and is
exited at only one place (e.g. a branch statement). Each basic block
consists of an expression tree. There are also classes to represent
try-catch blocks, Java subroutines (<tt>finally</tt> blocks), certain
properties of the control flow graph such as its dominator tree, and
to visualize a control flow graph.</p>
</body>
</html>

@ -0,0 +1,47 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
.SUFFIXES: .java .class
JAVA_HOME = /usr/local
CP := $(CLASSPATH)
#JAVA_HOME = /gcm/where/jdk/1.3/sparc.Solaris
JAVAC = $(JAVA_HOME)/bin/javac
JFLAGS = -g
CLASSPATH = $(JAVA_HOME)/lib/classes.zip:$(CP)
all: class
clean:
rm -f *.class
class:
@files=`$(MAKE) -n _class | grep $(JAVAC) | cut -d' ' -f4`; \
cpath=$(CLASSPATH):`(cd ../../../../..; pwd)`; \
if [ "x$$files" != "x" ]; then \
echo $(JAVAC) $(JFLAGS) -classpath $$cpath $$files; \
$(JAVAC) $(JFLAGS) -classpath $$cpath $$files; \
fi
_class: $(CLASS)
.java.class:
cpath=$(CLASSPATH):`(cd ../../../../..; pwd)`; \
$(JAVAC) -classpath $$cpath $<

File diff suppressed because it is too large Load Diff

@ -0,0 +1,823 @@
/*
* Class: Liveness
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.codegen;
import java.util.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.cfg.Handler;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MemRefExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
import edu.purdue.cs.bloat.util.Graph;
import edu.purdue.cs.bloat.util.GraphNode;
import edu.purdue.cs.bloat.util.ImmutableIterator;
/**
* Liveness represents the interference graph of the local variables contained
* in a control flow graph.
*
* When the liveness of two variables overlap each other, the two variables are
* said to <i>interfere</i> with each other. The interference graph represents
* this relationship between variables. There is an (un-directed) edge between
* variables <tt>a</tt> and <tt>b</tt> in the interference graph if variable
* <tt>a</tt> interferes with variable <tt>b</tt>.
*/
public class Liveness {
public static boolean DEBUG = false;
public static boolean UNIQUE = false;
public static final boolean BEFORE = false;
public static final boolean AFTER = true;
FlowGraph cfg;
Graph ig;
/**
* Constructor.
*
* @param cfg
* Control flow graph on which to perform liveness analysis.
*/
public Liveness(FlowGraph cfg) {
this.cfg = cfg;
computeIntersections();
}
/**
* Removes a local expression from the interference graph.
*/
public void removeVar(LocalExpr expr) {
ig.removeNode(expr);
}
/**
* Should not be called.
*/
public boolean liveAtUse(final VarExpr isLive, final VarExpr at,
final boolean after) {
throw new RuntimeException();
}
/**
* Should not be called.
*/
public boolean liveAtStartOfBlock(VarExpr isLive, Block block) {
throw new RuntimeException();
}
/**
* Should not be called.
*/
public boolean liveAtEndOfBlock(VarExpr isLive, Block block) {
throw new RuntimeException();
}
/**
* Returns the <tt>LocalExpr</tt>s (variables) that occur in the CFG.
* They correspond to nodes in the interference graph.
*/
public Collection defs() {
return ig.keySet();
}
/**
* Returns an <tt>Iterator</tt> of <tt>LocalExpr</tt>s that interfere
* with a given <tt>VarExpr</tt>.
*/
public Iterator intersections(VarExpr a) {
Assert.isTrue(a != null, "Cannot get intersections for null def");
Assert.isTrue(a.isDef(), "Cannot get intersections for variable uses");
final GraphNode node = ig.getNode(a);
Assert.isTrue(node != null, "Cannot find IG node for " + a);
return new Iterator() {
Iterator succs = ig.succs(node).iterator();
public boolean hasNext() {
return succs.hasNext();
}
public Object next() {
IGNode next = (IGNode) succs.next();
return next.def;
}
public void remove() {
throw new RuntimeException();
}
};
}
/**
* Determines whether or not two variables interfere with one another.
*/
public boolean liveRangesIntersect(VarExpr a, VarExpr b) {
Assert.isTrue(a != null && b != null,
"Cannot get intersections for null def");
Assert.isTrue(a.isDef() && b.isDef(),
"Cannot get intersections for variable uses");
if (a == b) {
return false;
}
// If all locals should have unique colors, return true.
if (UNIQUE) {
return true;
}
IGNode na = (IGNode) ig.getNode(a);
IGNode nb = (IGNode) ig.getNode(b);
Assert.isTrue(na != null && nb != null);
return ig.hasEdge(na, nb);
}
/**
* Constructs the interference graph.
*/
private void computeIntersections() {
ig = new Graph(); // The interference graph
if (Liveness.DEBUG) {
System.out.println("-----------Computing live ranges-----------");
}
// All of the nodes (IGNodes) in the IG
final List defNodes = new ArrayList();
// The IGNodes whose local variable is defined by a PhiCatchStmt
final List phiCatchNodes = new ArrayList();
// An array of NodeInfo for each node in the CFG (indexed by the
// node's pre-order index). Gives information about the local
// variables (nodes in the IG) that are defined in each block.
// The NodeInfos are stored in reverse order. That is, the
// NodeInfo for the final variable occurrence in the block is the
// first element in the list.
final List[] nodes = new ArrayList[cfg.size()];
// We need to keep track of the order of the statements in which
// variables occur. There is an entry in nodeIndices for each
// block in the CFG. Each entry consists of a mapping between a
// statement in which a variable occurs and the number of the
// statement (with respect to the other statements in which
// variables occur) of interest. This is hard to explain in
// words. This numbering comes into play in the liveOut method.
final Map[] nodeIndices = new LinkedHashMap[cfg.size()];
Iterator iter = cfg.nodes().iterator();
// Initialize nodes and nodeIndices
while (iter.hasNext()) {
Block block = (Block) iter.next();
int blockIndex = cfg.preOrderIndex(block);
nodes[blockIndex] = new ArrayList();
nodeIndices[blockIndex] = new LinkedHashMap();
}
// Go in trace order. Code generation for phis in the presence of
// critical edges depends on it!
iter = cfg.trace().iterator();
// When performing liveness analysis, we traverse the tree from
// the bottom up. That is, we do a REVERSE traversal.
while (iter.hasNext()) {
final Block block = (Block) iter.next();
block.visit(new TreeVisitor(TreeVisitor.REVERSE) {
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
if (!(stmt.target() instanceof LocalExpr)) {
return;
}
LocalExpr target = (LocalExpr) stmt.target();
// Examine each predacessor and maintain some
// information
// about the definitions. Remember that we're dealing
// with
// a PhiJoinStmt. The predacessors of PhiJoinStmts are
// statements that define or use the local (SSA)
// variable.
Iterator preds = cfg.preds(block).iterator();
while (preds.hasNext()) {
Block pred = (Block) preds.next();
int predIndex = cfg.preOrderIndex(pred);
List n = nodes[predIndex];
Map indices = nodeIndices[predIndex];
indices.put(stmt, new Integer(n.size()));
NodeInfo info = new NodeInfo(stmt);
n.add(info);
// Make a new node in the interference graph for target,
// if one does not already exists
IGNode node = (IGNode) ig.getNode(target);
if (node == null) {
node = new IGNode(target);
ig.addNode(target, node);
defNodes.add(node);
}
info.defNodes.add(node);
}
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
}
public void visitStmt(Stmt stmt) {
}
});
}
iter = cfg.trace().iterator();
while (iter.hasNext()) {
final Block block = (Block) iter.next();
final int blockIndex = cfg.preOrderIndex(block);
block.visit(new TreeVisitor(TreeVisitor.REVERSE) {
Node parent = null;
public void visitNode(Node node) {
Node p = parent;
parent = node;
node.visitChildren(this);
parent = p;
}
public void visitLocalExpr(LocalExpr expr) {
Assert.isTrue(parent != null);
// Recall that a LocalExpr represents a use or a
// definition
// of a local variable. If the LocalExpr is defined by a
// PhiJoinStmt, the block in which it resides should
// already
// have some information about it.
NodeInfo info;
List n = nodes[blockIndex];
Map indices = nodeIndices[blockIndex];
Integer i = (Integer) indices.get(parent);
if (i == null) {
if (DEBUG) {
System.out.println("adding " + parent + " at "
+ n.size());
}
indices.put(parent, new Integer(n.size()));
info = new NodeInfo(parent);
n.add(info);
} else {
if (DEBUG) {
System.out.println("found " + parent + " at " + i);
}
info = (NodeInfo) n.get(i.intValue());
Assert.isTrue(info != null);
}
if (expr.isDef()) {
IGNode node = (IGNode) ig.getNode(expr);
if (node == null) {
node = new IGNode(expr);
ig.addNode(expr, node);
defNodes.add(node);
}
info.defNodes.add(node);
}
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
NodeInfo info;
List n = nodes[blockIndex];
Map indices = nodeIndices[blockIndex];
Integer i = (Integer) indices.get(stmt);
if (i == null) {
if (DEBUG) {
System.out.println("adding " + stmt + " at "
+ n.size());
}
indices.put(stmt, new Integer(n.size()));
info = new NodeInfo(stmt);
n.add(info);
} else {
if (DEBUG) {
System.out.println("found " + parent + " at " + i);
}
info = (NodeInfo) n.get(i.intValue());
Assert.isTrue(info != null);
}
LocalExpr target = (LocalExpr) stmt.target();
IGNode node = (IGNode) ig.getNode(target);
if (node == null) {
node = new IGNode(target);
ig.addNode(target, node);
defNodes.add(node);
phiCatchNodes.add(node);
}
info.defNodes.add(node);
}
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
}
});
}
// Iterate over all of the nodes in the IG
int numDefs = defNodes.size();
for (int i = 0; i < numDefs; i++) {
IGNode node = (IGNode) defNodes.get(i);
LocalExpr def = node.def;
// Set of blocks where this variable is live out (i.e. live on
// any of the block's outgoing edges).
BitSet m = new BitSet(cfg.size());
Iterator uses = def.uses().iterator();
// Look at each use of the local variable
while (uses.hasNext()) {
LocalExpr use = (LocalExpr) uses.next();
Node parent = use.parent();
if (parent instanceof MemRefExpr
&& ((MemRefExpr) parent).isDef()) {
parent = parent.parent();
}
// Skip catch-phis. We handle this later.
if (parent instanceof PhiCatchStmt) {
// If we want to be less conservative:
// Need to search back from the operand from all
// points in the protected region where it is live
// back to the def of the operand. For each block
// in protected region, if the operand def is closest
// dominator of the block
continue;
}
if (DEBUG) {
System.out.println("searching for " + def + " from "
+ parent);
}
Block block = parent.block();
if (parent instanceof PhiJoinStmt) {
PhiJoinStmt phi = (PhiJoinStmt) parent;
// The local variable (LocalExpr) occurs within a
// PhiJoinStmt. Look at the predacessors of the
// PhiJoinStmt. Recall that each predacessor defines one
// of
// the operands to the PhiJoinStmt. Locate the block
// that
// defines the LocalExpr in question. Call liveOut to
// determine for which nodes the LocalExpr is live out.
// Examine the predacessors of the block containing the
// LocalExpr
Iterator preds = cfg.preds(block).iterator();
while (preds.hasNext()) {
Block pred = (Block) preds.next();
if (phi.operandAt(pred) == use) {
Map indices = nodeIndices[cfg.preOrderIndex(pred)];
Integer index = (Integer) indices.get(parent);
Assert.isTrue(index != null, "No index for "
+ parent);
liveOut(m, nodes, pred, index.intValue(), node,
phiCatchNodes);
break;
}
}
} else {
// The LocalExpr is define in a non-Phi statement.
// Figure
// out which number definition define the LocalExpr in
// quest
// and call liveOut to compute the set of block in which
// the
// LocalExpr is live out.
Map indices = nodeIndices[cfg.preOrderIndex(block)];
Integer index = (Integer) indices.get(parent);
Assert.isTrue(index != null, "No index for " + parent);
liveOut(m, nodes, block, index.intValue(), node,
phiCatchNodes);
}
}
}
// Go through all of the variables that are defined by
// PhiCatchStmts and make them (the variables) conflict with
// everything that the operands of the PhiCatchStmt conflict
// with. See liveOut for a discussion.
int numPhiCatches = phiCatchNodes.size();
for (int i = 0; i < numPhiCatches; i++) {
IGNode node = (IGNode) phiCatchNodes.get(i);
PhiCatchStmt phi = (PhiCatchStmt) node.def.parent();
Iterator operands = phi.operands().iterator();
while (operands.hasNext()) {
LocalExpr operand = (LocalExpr) operands.next();
LocalExpr def = (LocalExpr) operand.def();
if (def != null) {
IGNode opNode = (IGNode) ig.getNode(def);
// Conflict with everything the operand conflicts with.
Iterator edges = new ImmutableIterator(ig.succs(opNode));
while (edges.hasNext()) {
IGNode otherNode = (IGNode) edges.next();
if (otherNode != node) {
if (DEBUG) {
System.out.println(otherNode.def
+ " conflicts with " + opNode.def
+ " and thus with " + node.def);
}
ig.addEdge(otherNode, node);
ig.addEdge(node, otherNode);
}
}
}
}
}
if (DEBUG) {
System.out.println("Interference graph =");
System.out.println(ig);
}
}
/**
* Computes (a portion of) the "live out" set for a given local variable. If
* a variable is live on a block's outgoing edge in the CFG, then it is
* "live out" at that block.
*
* @param m
* Bit vector that indicates the block for which block the
* defNode is live out
* @param nodes
* The NodeInfo for the local variables used or defined in each
* block
* @param block
* The block in which the LocalExpr of interest is defined
* @param nodeIndex
* Which number definition in the defining block
* @param defNode
* The node in the IG whose live out set we are interested in
* @param phiCatchNode
* The nodes in the interference graph that represent local
* variables defined by PhiCatchStmts
*/
// Nate sez:
//
// In a PhiJoin pred, add
// ...
// phi-target := phi-operand
// jump with throw succs
//
// Don't kill Phi targets in protected blocks
// The phi target and operand don't conflict
void liveOut(BitSet m, List[] nodes, Block block, int nodeIndex,
IGNode defNode, Collection phiCatchNodes) {
boolean firstNode = true;
int blockIndex = cfg.preOrderIndex(block);
ArrayList stack = new ArrayList();
Pos pos = new Pos();
pos.block = block;
pos.blockIndex = blockIndex;
pos.nodeIndex = nodeIndex;
stack.add(pos);
while (!stack.isEmpty()) {
pos = (Pos) stack.remove(stack.size() - 1);
block = pos.block;
blockIndex = pos.blockIndex;
nodeIndex = pos.nodeIndex;
if (DEBUG) {
System.out.println(defNode.def + " is live at position "
+ nodeIndex + " of " + block);
}
boolean stop = false;
// The nodes are sorted in reverse. So, the below gets all of
// the nodes defined at this block after nodeIndex. I believe
// this is an optimization so we don't calculate things twice.
// Or maybe its how we get things to terminate.
ListIterator iter = nodes[blockIndex].listIterator(nodeIndex);
while (!stop && iter.hasNext()) {
NodeInfo info = (NodeInfo) iter.next();
if (DEBUG) {
System.out
.println(defNode.def + " is live at " + info.node);
}
if (firstNode) {
// We don't care about the definition in the block that
// defines the LocalExpr of interest.
firstNode = false;
continue;
}
// Look at all (?) of the definitions of the LocalExpr
Iterator e = info.defNodes.iterator();
while (e.hasNext()) {
IGNode node = (IGNode) e.next();
Iterator catchPhis = phiCatchNodes.iterator();
// Calculating the live region of the target of a
// phi-catch
// node is a little tricky. The target (variable) must
// be
// live throughout the protected region as well as after
// the
// PhiCatchStmt (its definition). However, we do not
// want
// the phi-catch target to conflict (interfere) with any
// of
// its operands. So, we make the target conflict with
// all
// of the variables that its operand conflict with. See
// page 37 of Nate's Thesis.
PHIS: while (catchPhis.hasNext()) {
IGNode catchNode = (IGNode) catchPhis.next();
PhiCatchStmt phi = (PhiCatchStmt) catchNode.def
.parent();
Handler handler = (Handler) cfg.handlersMap().get(
phi.block());
Assert.isTrue(handler != null, "Null handler for "
+ phi.block());
if (handler.protectedBlocks().contains(block)) {
Iterator operands = phi.operands().iterator();
// If the block containing the LocalExpr in
// question
// resides inside a protected region. Make sure
// that
// the LocalExpr is not one of the operands to
// the
// PhiCatchStmt associated with the protected
// region.
while (operands.hasNext()) {
LocalExpr expr = (LocalExpr) operands.next();
if (expr.def() == node.def) {
continue PHIS;
}
}
if (DEBUG) {
System.out.println(defNode.def
+ " conflicts with " + node.def);
}
// Hey, wow. The variable defined in the
// phi-catch
// interferes with the variable from the
// worklist.
ig.addEdge(node, catchNode);
ig.addEdge(catchNode, node);
}
}
if (node != defNode) {
if (DEBUG) {
System.out.println(defNode.def + " conflicts with "
+ node.def);
}
// If the node in the worklist is not the node we
// started
// with, then they conflict.
ig.addEdge(node, defNode);
ig.addEdge(defNode, node);
} else {
if (DEBUG) {
System.out.println("def found stopping search");
}
// We've come across a definition of the LocalExpr in
// question, so we don't need to do any more.
stop = true;
}
}
}
if (!stop) {
// Propagate the liveness to each of the predacessors of the
// block in which the variable of interest is defined. This
// is accomplished by setting the appropriate bit in m. We
// also add another Pos to the worklist to work on the
// predacessor block.
Iterator preds = cfg.preds(block).iterator();
while (preds.hasNext()) {
Block pred = (Block) preds.next();
int predIndex = cfg.preOrderIndex(pred);
if (DEBUG) {
System.out.println(defNode.def + " is live at end of "
+ pred);
}
if (!m.get(predIndex)) {
pos = new Pos();
pos.block = pred;
pos.blockIndex = predIndex;
// Look at all of the statements in which a variable
// occur
pos.nodeIndex = 0;
m.set(predIndex);
stack.add(pos);
}
}
}
}
}
/**
* Represents a node in the interference graph. Connected nodes in the
* interference graph interfere with each other. That is, their live regions
*/
class IGNode extends GraphNode {
LocalExpr def;
/**
* Constructor.
*
* @param def
* The local variable represented by this node.
*/
public IGNode(LocalExpr def) {
this.def = def;
}
public String toString() {
return def.toString();
}
}
/**
* Stores information about each Node in an expression tree (!) that defines
* a local variable (i.e. PhiJoinStmt, PhiCatchStmt, and the parent of a
* LocalExpr).
*/
class NodeInfo {
Node node; // Node in an expression tree in which a variable occurs
List defNodes; // node(s) in IG that define above Node
public NodeInfo(Node node) {
this.node = node;
defNodes = new ArrayList();
}
}
class Key {
int blockIndex;
Node node;
public Key(Node node, int blockIndex) {
this.blockIndex = blockIndex;
this.node = node;
}
public int hashCode() {
return node.hashCode() ^ blockIndex;
}
public boolean equals(Object obj) {
if (obj instanceof Key) {
Key key = (Key) obj;
return key.node == node && key.blockIndex == blockIndex;
}
return false;
}
}
/**
* A Pos is an element in the worklist used to determine the live out set of
* a given LocalExpr. It consists of the block in which a local variable
* definition occurs, the block's index (i.e. pre-order traversal number) in
* the CFG, and the number of the definition in the block that defines the
* LocalExpr of interest.
*/
class Pos {
Block block;
int blockIndex;
int nodeIndex;
}
}

@ -0,0 +1,27 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
CodeGenerator.class\
Liveness.class\
RegisterAllocator.class
include ../class.mk

@ -0,0 +1,752 @@
/*
* Class: RegisterAllocator
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.codegen;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.InitStmt;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
import edu.purdue.cs.bloat.util.Graph;
import edu.purdue.cs.bloat.util.GraphNode;
import edu.purdue.cs.bloat.optimize.Optimization;
import java.util.*;
/**
* RegisterAllocator performs analysis on a control flow graph and determines
* the minimum amount of local variables needed in a method.
*
* @see LocalVariable
*/
// Note that RegisterAllocator uses a different IGNode from Liveness!
public class RegisterAllocator implements Optimization {
FlowGraph cfg;
Liveness liveness;
Map colors;
int colorsUsed;
final static float MAX_WEIGHT = Float.MAX_VALUE;
final static float LOOP_FACTOR = 10.0F;
final static int MAX_DEPTH = (int) (Math.log(MAX_WEIGHT) / Math
.log(LOOP_FACTOR));
public void transform(MethodState state) {
transform(state.cfg(), new Liveness(state.cfg()));
}
public String traceMessage(String dateString) {
return "";
}
/*
* Print a debugging message. Called before #transform().
*
* @see edu.purdue.cs.bloat.optimize.Optimization#preDebugMessage()
*/
public String preDebugMessage() {
return "";
}
/*
* Print a debugging message. Called after #transform().
*
* @see edu.purdue.cs.bloat.optimize.Optimization#postDebugMessage()
*/
public String postDebugMessage() {
return "";
}
/**
* Constructor. Builds an interference graph based on the expression nodes
* found in liveness. Traverses the graph and determines which nodes needs
* to be precolored and which nodes can be coalesced (move statements).
* Nodes are coalesced and local variables are assigned to expressions.
*
* @see FlowGraph
* @see LocalVariable
*/
public void transform(FlowGraph cfg, Liveness liveness) {
this.cfg = cfg;
this.liveness = liveness;
colorsUsed = 0;
colors = new LinkedHashMap();
// Construct the interference graph.
final Graph ig = new Graph();
Iterator iter = liveness.defs().iterator();
while (iter.hasNext()) {
VarExpr def = (VarExpr) iter.next();
if (!(def instanceof LocalExpr)) {
// Ignore node in the Liveness IG that are not LocalExprs
continue;
}
// Create a new node in the IG, if one does not already exist
IGNode defNode = (IGNode) ig.getNode(def);
if (defNode == null) {
defNode = new IGNode((LocalExpr) def);
ig.addNode(def, defNode);
}
// Examine each variable that interferes with def
Iterator intersections = liveness.intersections(def);
while (intersections.hasNext()) {
VarExpr expr = (VarExpr) intersections.next();
if (expr == def) {
// If for some reason, def interferes with itself,
// ignore it
continue;
}
// Add an edge in RegisterAllocator's IG between the variables
// that interfere
if (expr instanceof LocalExpr) {
IGNode node = (IGNode) ig.getNode(expr);
if (node == null) {
node = new IGNode((LocalExpr) expr);
ig.addNode(expr, node);
}
ig.addEdge(defNode, node);
ig.addEdge(node, defNode);
}
}
}
// Arrays of expressions that invovle a copy of one local variable
// to another. Expressions invovled in copies (i.e. "moves") can
// be coalesced into one expression.
// MODIFIED
final ArrayList copies = new ArrayList();
// Nodes that are the targets of InitStmt are considered to be
// precolored.
final ArrayList precolor = new ArrayList();
cfg.visit(new TreeVisitor() {
/*
*/
public void visitBlock(Block block) {
// Don't visit the sink block. There's nothing interesting
// there.
if (block != RegisterAllocator.this.cfg.sink()) {
block.visitChildren(this);
}
}
public void visitPhiStmt(PhiStmt stmt) {
stmt.visitChildren(this);
if (!(stmt.target() instanceof LocalExpr)) {
return;
}
// A PhiStmt invovles an assignment (copy). So note the copy
// between the target and all of the PhiStmt's operands in the
// copies list.
IGNode lnode = (IGNode) ig.getNode(stmt.target());
HashSet set = new LinkedHashSet();
Iterator e = stmt.operands().iterator();
while (e.hasNext()) {
Expr op = (Expr) e.next();
if (op instanceof LocalExpr && op.def() != null) {
if (!set.contains(op.def())) {
set.add(op.def());
if (op.def() != stmt.target()) {
IGNode rnode = (IGNode) ig.getNode(op.def());
copies.add(new IGNode[] { lnode, rnode });
}
}
}
}
}
public void visitStoreExpr(StoreExpr expr) {
expr.visitChildren(this);
if (!(expr.target() instanceof LocalExpr)) {
return;
}
IGNode lnode = (IGNode) ig.getNode(expr.target());
if (expr.expr() instanceof LocalExpr
&& expr.expr().def() != null) {
// A store of a variable into another variable is a copy
IGNode rnode = (IGNode) ig.getNode(expr.expr().def());
copies.add(new IGNode[] { lnode, rnode });
return;
}
// Treat L := L + k as a copy so that they get converted
// back to iincs.
if (expr.target().type().equals(Type.INT)) {
if (!(expr.expr() instanceof ArithExpr)) {
return;
}
// We're dealing with integer arithmetic. Remember that
// an
// ArithExpr has a left and a right operand. If one of
// the
// operands is a variable and if the other is a constant
// and
// the operation is addition or substraction, we have an
// increment.
ArithExpr rhs = (ArithExpr) expr.expr();
LocalExpr var = null;
Integer value = null;
if (rhs.left() instanceof LocalExpr
&& rhs.right() instanceof ConstantExpr) {
var = (LocalExpr) rhs.left();
ConstantExpr c = (ConstantExpr) rhs.right();
if (c.value() instanceof Integer) {
value = (Integer) c.value();
}
} else if (rhs.right() instanceof LocalExpr
&& rhs.left() instanceof ConstantExpr) {
var = (LocalExpr) rhs.right();
ConstantExpr c = (ConstantExpr) rhs.left();
if (c.value() instanceof Integer) {
value = (Integer) c.value();
}
}
if (rhs.operation() == ArithExpr.SUB) {
if (value != null) {
value = new Integer(-value.intValue());
}
} else if (rhs.operation() != ArithExpr.ADD) {
value = null;
}
if (value != null && var.def() != null) {
int incr = value.intValue();
if ((short) incr == incr) {
// Only generate an iinc if the increment
// fits in a short
IGNode rnode = (IGNode) ig.getNode(var.def());
copies.add(new IGNode[] { lnode, rnode });
}
}
}
}
/*
*/
public void visitInitStmt(InitStmt stmt) {
stmt.visitChildren(this);
// The initialized variables are precolored.
LocalExpr[] t = stmt.targets();
for (int i = 0; i < t.length; i++) {
precolor.add(t[i]);
}
}
});
// Coalesce move related nodes, maximum weight first.
/*
*/
while (copies.size() > 0) {
// We want the copy (v <- w) with the maximum:
// weight(v) + weight(w)
// ---------------------
// size(union)
// where union is the intersection of the nodes that conflict
// with v and the nodes that conflict with w. This equation
// appears to be in conflict with the one given on page 38 of
// Nate's thesis.
HashSet union; // The union of neighboring nodes
int max = 0;
IGNode[] copy = (IGNode[]) copies.get(max);
float maxWeight = copy[0].weight + copy[1].weight;
union = new LinkedHashSet();
union.addAll(ig.succs(copy[0]));
union.addAll(ig.succs(copy[1]));
maxWeight /= union.size();
for (int i = 1; i < copies.size(); i++) {
copy = (IGNode[]) copies.get(i);
float weight = copy[0].weight + copy[1].weight;
union.clear();
union.addAll(ig.succs(copy[0]));
union.addAll(ig.succs(copy[1]));
weight /= union.size();
if (weight > maxWeight) {
// The ith copy has the maximum weight
maxWeight = weight;
max = i;
}
}
// Remove the copy with the max weight from the copies list. He
// does it in a rather round-about way.
copy = (IGNode[]) copies.get(max);
copies.set(max, copies.get(copies.size() - 1));
copies.remove(copies.size() - 1);
if (!ig.hasEdge(copy[0], copy[1])) {
// If the variables involved in the copy do not interfere with
// each other, they are coalesced.
if (CodeGenerator.DEBUG) {
System.out.println("coalescing " + copy[0] + " " + copy[1]);
System.out.println(" 0 conflicts " + ig.succs(copy[0]));
System.out.println(" 1 conflicts " + ig.succs(copy[1]));
}
ig.succs(copy[0]).addAll(ig.succs(copy[1]));
ig.preds(copy[0]).addAll(ig.preds(copy[1]));
copy[0].coalesce(copy[1]);
if (CodeGenerator.DEBUG) {
System.out.println(" coalesced " + copy[0]);
System.out.println(" conflicts " + ig.succs(copy[0]));
}
// Remove coalesced node from the IG
ig.removeNode(copy[1].key);
iter = copies.iterator();
// Examine all copies. If the copy involves the node that was
// coalesced, the copy is no longer interesting. Remove it.
while (iter.hasNext()) {
IGNode[] c = (IGNode[]) iter.next();
if (c[0] == copy[1] || c[1] == copy[1]) {
iter.remove();
}
}
}
}
/*
*/
// Create a list of uncolored nodes.
ArrayList uncoloredNodes = new ArrayList();
Iterator nodes = ig.nodes().iterator();
while (nodes.hasNext()) {
IGNode node = (IGNode) nodes.next();
ArrayList p = new ArrayList(precolor);
p.retainAll(node.defs);
// See if any node got coalesced with a precolored node.
if (p.size() == 1) {
// Precolored
node.color = ((LocalExpr) p.get(0)).index();
if (CodeGenerator.DEBUG) {
System.out.println("precolored " + node + " " + node.color);
}
} else if (p.size() == 0) {
// Uncolored (i.e. not coalesced with any of the pre-colored
// nodes.
node.color = -1;
uncoloredNodes.add(node);
} else {
// If two or more pre-colored nodes were coalesced, we have a
// problem.
throw new RuntimeException("coalesced pre-colored defs " + p);
}
}
// MOD
/*
* Iterator inits = precolor.iterator(); while (inits.hasNext()) {
* VarExpr def = (VarExpr) inits.next(); IGNode defNode = (IGNode)
* ig.getNode(def);
*
* Iterator succs = ig.succs(defNode).iterator();
*
*
* if (defNode.wide) { // Wide variables need two colors defNode.color =
* colorsUsed;
*
* if (CodeGenerator.DEBUG) { System.out.println(" assigning color " +
* colorsUsed + " to " + defNode); } colorsUsed=colorsUsed+2; ; } else {
* defNode.color = colorsUsed;
*
* if (CodeGenerator.DEBUG) { System.out.println(" assigning color " +
* colorsUsed + " to " + defNode); } colorsUsed++; } }
*
*/
// END MOD
// Sort the uncolored nodes, by decreasing weight. Wide nodes
// have half their original weight since they take up two indices
// and we want to put color nodes with the lower indices.
Collections.sort(uncoloredNodes, new Comparator() {
public int compare(Object a, Object b) {
IGNode na = (IGNode) a;
IGNode nb = (IGNode) b;
float wa = na.weight / ig.succs(na).size();
float wb = nb.weight / ig.succs(nb).size();
if (na.wide) {
wa /= 2;
}
if (nb.wide) {
wb /= 2;
}
if (wb > wa) {
return 1;
}
if (wb < wa) {
return -1;
}
return 0;
}
});
nodes = uncoloredNodes.iterator();
while (nodes.hasNext()) {
IGNode node = (IGNode) nodes.next();
if (CodeGenerator.DEBUG) {
System.out.println("coloring " + node);
System.out.println(" conflicts " + ig.succs(node));
}
// Make sure node has not been colored
Assert.isTrue(node.color == -1);
// Determine which colors have been assigned to the nodes
// conflicting with the node of interest
BitSet used = new BitSet();
Iterator succs = ig.succs(node).iterator();
while (succs.hasNext()) {
IGNode succ = (IGNode) succs.next();
if (succ.color != -1) {
used.set(succ.color);
if (succ.wide) {
used.set(succ.color + 1);
}
}
}
// Find the next available color
for (int i = 0; node.color == -1; i++) {
if (!used.get(i)) {
if (node.wide) {
// Wide variables need two colors
if (!used.get(i + 1)) {
node.color = i;
if (CodeGenerator.DEBUG) {
System.out.println(" assigning color " + i
+ " to " + node);
}
if (i + 1 >= colorsUsed) {
colorsUsed = i + 2;
}
}
} else {
node.color = i;
if (CodeGenerator.DEBUG) {
System.out.println(" assigning color " + i
+ " to " + node);
}
if (i >= colorsUsed) {
colorsUsed = i + 1;
}
}
}
}
}
nodes = ig.nodes().iterator();
while (nodes.hasNext()) {
IGNode node = (IGNode) nodes.next();
// Make sure each node has been colored
Assert.isTrue(node.color != -1, "No color for " + node);
iter = node.defs.iterator();
// Set the index of the variable and all of its uses to be the
// chosen color.
while (iter.hasNext()) {
LocalExpr def = (LocalExpr) iter.next();
def.setIndex(node.color);
Iterator uses = def.uses().iterator();
while (uses.hasNext()) {
LocalExpr use = (LocalExpr) uses.next();
use.setIndex(node.color);
}
}
}
if (CodeGenerator.DEBUG) {
System.out.println("After allocating locals--------------------");
cfg.print(System.out);
System.out.println("End print----------------------------------");
}
}
/**
* Returns the maximum number of local variables used by the cfg after its
* "registers" (local variables) have been allocated.
*/
public int maxLocals() {
return colorsUsed;
}
/**
* Creates a new local variable in this method (as modeled by the cfg).
* Updates the number of local variables appropriately.
*/
public LocalVariableGen newLocal(Type type) {
// Why don't we add Type information to the LocalVariable? Are we
// assuming that type checking has already been done and so its a
// moot point?
LocalVariableGen var = new LocalVariableGen(colorsUsed, "retAdr"
+ colorsUsed, type, null, null);
colorsUsed += type.getSize();
return var;
}
/**
* IGNode is a node in the interference graph. Note that this node is
* different from the one in Liveness. For instance, this one stores
* information about a node's color, its weight, etc. Because nodes may be
* coalesced, an IGNode may represent more than one LocalExpr. That's why
* there is a list of definitions.
*/
class IGNode extends GraphNode {
Set defs;
LocalExpr key;
int color;
boolean wide; // Is the variable wide?
float weight;
public IGNode(LocalExpr def) {
color = -1;
key = def;
defs = new LinkedHashSet();
defs.add(def);
wide = (def.type().getSize() == 2);
computeWeight();
}
/**
* Coalesce two nodes in the interference graph. The weight of the other
* node is added to that of this node. This node also inherits all of
* the definitions of the other node.
*/
void coalesce(IGNode node) {
Assert.isTrue(wide == node.wide);
weight += node.weight;
Iterator iter = node.defs.iterator();
while (iter.hasNext()) {
LocalExpr def = (LocalExpr) iter.next();
defs.add(def);
}
}
public String toString() {
return "(color=" + color + " weight=" + weight + " "
+ defs.toString() + ")";
}
/**
* Calculates the weight of a Block based on its loop depth. If the
* block does not exceed the MAX_DEPTH, then the weight is LOOP_FACTOR
* raised to the depth.
*/
private float blockWeight(Block block) {
int depth = cfg.loopDepth(block);
if (depth > MAX_DEPTH) {
return MAX_WEIGHT;
}
float w = 1.0F;
while (depth-- > 0) {
w *= LOOP_FACTOR;
}
return w;
}
/**
* Computes the weight of a node in the interference graph. The weight
* is based on where the variable represented by this node is used. The
* method blockWeight is used to determine the weight of a variable used
* in a block based on the loop depth of the block. Special care must be
* taken if the variable is used in a PhiStmt.
*/
private void computeWeight() {
weight = 0.0F;
Iterator iter = defs.iterator();
// Look at all(?) of the definitions of the IGNode
while (iter.hasNext()) {
LocalExpr def = (LocalExpr) iter.next();
weight += blockWeight(def.block());
Iterator uses = def.uses().iterator();
// If the variable is used as an operand to a PhiJoinStmt,
// find the predacessor block to the PhiJoinStmt in which the
// variable occurs and add the weight of that block to the
// running total weight.
while (uses.hasNext()) {
LocalExpr use = (LocalExpr) uses.next();
if (use.parent() instanceof PhiJoinStmt) {
PhiJoinStmt phi = (PhiJoinStmt) use.parent();
Iterator preds = cfg.preds(phi.block()).iterator();
while (preds.hasNext()) {
Block pred = (Block) preds.next();
Expr op = phi.operandAt(pred);
if (use == op) {
weight += blockWeight(pred);
break;
}
}
} else if (use.parent() instanceof PhiCatchStmt) {
// If the variable is used in a PhiCatchStmt, add the
// weight of the block in which the variable is defined
// to
// the running total.
weight += blockWeight(use.def().block());
} else {
// Just add in the weight of the block in which the
// variable is used.
weight += blockWeight(use.block());
}
}
}
}
}
}

@ -0,0 +1,9 @@
<html>
<body>
<p>Generates Java bytecodes from the contents of a control flow graph.
It also performs "register" allocation of the local variables inside
the virtual machine.</p>
</body>
</html>

@ -0,0 +1,295 @@
/*
* Class: BloatContext
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.context;
import org.apache.bcel.generic.*;
import org.apache.bcel.util.Repository;
import org.apache.bcel.verifier.structurals.UninitializedObjectType;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.editor.MethodRef;
import edu.purdue.cs.bloat.inline.CallGraph;
import edu.purdue.cs.bloat.inline.InlineContext;
import edu.purdue.cs.bloat.inline.InlineStats;
import java.io.*;
import java.util.*;
/**
* This abstract class is a central repository for all things that are necessary
* for a BLOATing sessions. Its subclasses implement certain schemes for
* managing BLOAT data structures such as editors and control flow graphs.
*/
public abstract class BloatContext implements InlineContext {
public static boolean DEBUG = Boolean.getBoolean("BloatContext.DEBUG");
protected InlineStats inlineStats;
// Ignore stuff for inlining
protected Set ignorePackages = new LinkedHashSet();
protected Set ignoreClasses = new LinkedHashSet();
protected Set ignoreMethods = new LinkedHashSet();
protected Set ignoreFields = new LinkedHashSet();
protected boolean ignoreSystem = false;
protected CallGraph callGraph;
protected Set roots; // Root methods of call graph
protected static void db(String s) {
if (DEBUG)
System.out.println(s);
}
protected Repository loader;
/**
* Constructor. Each <tt>BloatContext</tt> needs to know about a
* <tt>ClassInfoLoader</tt>.
*/
public BloatContext(Repository loader) {
this.loader = loader;
}
private static ClassLoader systemCL;
static {
String s = "";
systemCL = s.getClass().getClassLoader();
}
/**
* Returns <tt>true</tt> if the give type is a system class (that is, has
* the same class loader as java.lang.String).
*/
public static boolean isSystem(ObjectType type) {
Class c = null;
try {
c = Class.forName(type.getClassName().replace('/', '.'));
} catch (ClassNotFoundException ex) {
System.err
.println("** Could not find class " + type.getClassName());
ex.printStackTrace(System.err);
System.exit(1);
}
// Have to use == because class loader might be null
return (c.getClassLoader() == systemCL);
}
public void setRootMethods(Set roots) {
if (this.callGraph != null) {
// Can't set the call graph roots after its been created
throw new IllegalStateException("Cannot set roots after "
+ "call graph has been created");
}
this.roots = roots;
}
public CallGraph getCallGraph() {
if (this.callGraph == null) {
// Create a new CallGraph
this.callGraph = new CallGraph(this, this.roots);
}
return (this.callGraph);
}
public InlineStats getInlineStats() {
if (inlineStats == null) {
inlineStats = new InlineStats();
}
return (inlineStats);
}
public void addIgnorePackage(String name) {
name = name.replace('.', '/');
ignorePackages.add(name);
}
public void addIgnoreClass(Type type) {
ignoreClasses.add(type);
}
public void addIgnoreMethod(MethodRef method) {
ignoreMethods.add(method);
}
public void addIgnoreField(MemberRef field) {
ignoreFields.add(field);
}
public void setIgnoreSystem(boolean ignore) {
this.ignoreSystem = ignore;
}
public boolean ignoreClass(Type type) {
// First, check to see if we explicitly ignore it. If not, check
// to see if we ignore its package. The ladies always seem to
// ignore my package.
if (type instanceof ReferenceType)
if (type instanceof ArrayType)
type = ((ArrayType) type).getBasicType();
else if (type instanceof UninitializedObjectType)
type = ((UninitializedObjectType) type).getInitialized();
// CONVERT ARRAYTYPES ETC TO OBJECTTYPES OR BASICTYPES
if (ignoreClasses.contains(type)) {
return (true);
} else if (type instanceof BasicType) {
addIgnoreClass(type);
return (true);
} else {
ObjectType objType = (ObjectType) type;
if (this.ignoreSystem) {
if (isSystem(objType)) {
addIgnoreClass(objType);
return (true);
}
}
String packageName = objType.getClassName();
int lastSlash = packageName.lastIndexOf('/');
if (lastSlash == -1) {
return (false);
}
packageName = packageName.substring(0, lastSlash);
// If any ignore package is a prefix of the class's package,
// then ignore it. This makes our lives easier.
Iterator packages = ignorePackages.iterator();
while (packages.hasNext()) {
String s = (String) packages.next();
if (objType.getClassName().startsWith(s)) {
addIgnoreClass(type);
return (true);
}
}
return (false);
}
}
public boolean ignoreMethod(MethodRef method) {
if (ignoreMethods.contains(method)) {
return (true);
} else if (ignoreClass(method.declaringClass())) {
addIgnoreMethod(method);
return (true);
}
return (false);
}
public boolean ignoreField(MemberRef field) {
if (ignoreMethods.contains(field)) {
return (true);
} else if (ignoreClass(field.declaringClass())) {
addIgnoreField(field);
return (true);
}
return (false);
}
/**
* Commits all classes, methods, and fields, that have been modified.
*/
public abstract void commitDirty();
/**
* Test the ignore stuff.
*/
public static void main(String[] args) {
PrintWriter out = new PrintWriter(System.out, true);
PrintWriter err = new PrintWriter(System.err, true);
BloatContext context = new PersistentBloatContext(
org.apache.bcel.Repository.getRepository());
// new CachingBloatContext(new ClassFileLoader(), new ArrayList(),
// false);
List types = new ArrayList();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-ip")) {
if (++i >= args.length) {
err.println("** Missing package name");
System.exit(1);
}
out.println("Ignoring package " + args[i]);
context.addIgnorePackage(args[i]);
} else if (args[i].equals("-ic")) {
if (++i >= args.length) {
err.println("** Missing class name");
System.exit(1);
}
out.println("Ignoring class " + args[i]);
String type = args[i].replace('.', '/');
context.addIgnoreClass(Type.getType("L" + type + ";"));
} else {
// A type
String type = args[i].replace('.', '/');
types.add(Type.getType("L" + type + ";"));
}
}
out.println("");
Iterator iter = types.iterator();
while (iter.hasNext()) {
Type type = (Type) iter.next();
out.println("Ignore " + type + "? " + context.ignoreClass(type));
}
}
}

@ -0,0 +1,26 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
BloatContext.class\
PersistentBloatContext.class
include ../class.mk

@ -0,0 +1,483 @@
/*
* Class: PersistentBloatContext
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.context;
import org.apache.bcel.verifier.structurals.UninitializedObjectType;
import org.apache.bcel.util.Repository;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import edu.purdue.cs.bloat.editor.ClassHierarchy;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.editor.MethodRef;
import edu.purdue.cs.bloat.editor.NameAndType;
import java.util.*;
/**
* Maintains all BLOAT data structures as if they were meant to reside in a
* persistent store. As a result, it keeps every piece of BLOAT data around
* because it might be needed in the future. No fancing cache maintainence is
* performed. Because we are going for maximum information we take the closure
* of classes when working with the class hierarchy.
*/
public class PersistentBloatContext extends BloatContext {
protected final ClassHierarchy hierarchy;
protected Map classEditors; // Maps ClassInfos to ClassEditors
protected Map classInfos; // Maps ClassInfos to ClassEditors
public static boolean DB_COMMIT = true;
protected static void comm(String s) {
if (DB_COMMIT || DEBUG) {
System.out.println(s);
}
}
/**
* Constructor. Each <tt>BloatContext</tt> stems from a
* <tt>ClassInfoLoader</tt>. Using the loader it can create an
* <tt>Editor</tt> and such. Initially, no classes are loaded.
*/
public PersistentBloatContext(Repository loader) {
this(loader, true);
}
/**
* Constructor. It is the responsibility of the subclasses to add classes to
* the hierarchy by calling <tt>addClasses</tt>.
*
* @param loader
* Used to load classes
* @param closure
* Do we look for the maximum number of classes?
*/
public PersistentBloatContext(Repository loader, boolean closure) {
super(loader);
db("Creating a new BloatContext");
// Create a bunch of the mappings we maintain. Make sure to do
// this before anything else!
classEditors = new LinkedHashMap();
classInfos = new LinkedHashMap();
// Have to create an empty class hierarchy then add the classes.
// There is a strange circular dependence between the hierarchy
// and the context.
this.hierarchy = new ClassHierarchy(this, new ArrayList(), closure);
}
/**
* Adds a bunch of (names of) classes to the hierarchy.
*/
protected void addClasses(Collection classes) {
Iterator iter = classes.iterator();
while (iter.hasNext()) {
String className = (String) iter.next();
this.hierarchy.addClassNamed(className);
}
}
public JavaClass loadClass(String className) throws ClassNotFoundException {
// Lots of interesting stuff to do here. For the moment, just
// load the class from the ClassInfoLoader and add it to the
// hierarchy.
className = className.replace('.', '/');
// Check the cache of ClassInfos
JavaClass info = (JavaClass) classInfos.get(className);
if (info == null) {
db("BloatContext: Loading class " + className);
info = loader.loadClass(className);
hierarchy.addClassNamed(className);
db("loadClass: " + className + " -> " + info);
classInfos.put(className, info);
}
return (info);
}
public JavaClass newClassInfo(int class_name_index,
int superclass_name_index, String file_name, int major, int minor,
int access_flags, ConstantPool constant_pool, int[] interfaces,
Field[] fields, Method[] methods, Attribute[] attributes) {
JavaClass jc = new JavaClass(class_name_index, superclass_name_index,
file_name, major, minor, access_flags, constant_pool,
interfaces, fields, methods, attributes);
String className = jc.getClassName();
db("newClassEditor(...........): " + className + " -> " + jc);
classInfos.put(className, jc);
return jc;
}
public ClassGen newClass(int accessflags, String className,
String file_name, Type superType, Type[] interfaces) {
String[] interNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
interNames[i] = ((ObjectType) interfaces[i]).getClassName();
}
ClassGen cg = new ClassGen(className, ((ObjectType) superType)
.getClassName(), file_name, accessflags, interNames);
JavaClass jc = cg.getJavaClass();
String classname = cg.getClassName();
db("newClassInfo(.....): " + classname + " -> " + cg);
classEditors.put(classname, cg);
classInfos.put(classname, jc);
return cg;
}
/*
* public ClassInfo newClassInfo(int modifiers, int classIndex, int
* superClassIndex, int[] interfaceIndexes, List constants) {
*
* return this.loader.storeClass(modifiers, classIndex, superClassIndex,
* interfaceIndexes, constants); }
*/
public ClassHierarchy getHierarchy() {
return (this.hierarchy);
}
public ClassGen newClass(int class_name_index, int superclass_name_index,
String file_name, int major, int minor, int access_flags,
ConstantPool constant_pool, int[] interfaces, Field[] fields,
Method[] methods, Attribute[] attributes) {
JavaClass jc = new JavaClass(class_name_index, superclass_name_index,
file_name, major, minor, access_flags, constant_pool,
interfaces, fields, methods, attributes);
ClassGen ce = new ClassGen(jc);
String className = ce.getClassName();
db("editClass(ClassInfo): " + className + " -> " + ce);
classEditors.put(className, ce);
classInfos.put(className, jc);
return ce;
}
public ClassGen editClass(String className) throws ClassNotFoundException,
ClassFormatException {
// Only make the name -> classInfo mapping if we edit the class,
// this way the mapping will be deleted when the ClassEditor is
// released.
// className = className.intern();
ClassGen info = (ClassGen) classEditors.get(className);
if (info == null) {
JavaClass jc = loadClass(className);
db("editClass(String): " + className + " -> " + info);
return editClass(jc);
}
return (info);
}
public ClassGen editClass(Type classType) throws ClassNotFoundException,
ClassFormatException {
if (classType instanceof ReferenceType) {
if (classType instanceof ObjectType)
return editClass((ObjectType) classType);
else if (classType instanceof ArrayType)
return editClass(((ArrayType) classType).getBasicType());
else if (classType instanceof UninitializedObjectType)
return editClass(((UninitializedObjectType) classType)
.getInitialized());
} else
throw new ClassNotFoundException(classType
+ "is not an ObjectType and cannot be loaded");
return null;
}
public ClassGen editClass(ObjectType classType)
throws ClassNotFoundException, ClassFormatException {
return (editClass(classType.getClassName()));
}
public ClassGen editClass(JavaClass info) {
// Check the cache
ClassGen ce = (ClassGen) classEditors.get(info.getClassName());
if (ce == null) {
ce = new ClassGen(info);
classInfos.put(info.getClassName(), info);
classEditors.put(info.getClassName(), ce);
// if(!classInfos.containsValue(info)) {
// String className = ce.getClassName().intern();
// db("editClass(ClassInfo): " + className + " -> " + info);
// classInfos.put(className, info);
// }
}
return (ce);
}
public MethodGen editMethod(MethodRef method) throws NoSuchMethodException {
// Groan, we have to do this the HARD way.
db("Creating a new MethodEditor for " + method);
String name = method.name();
String signature = method.getSignature();
try {
ClassGen ce = editClass(method.declaringClass());
Method[] methods = ce.getMethods();
for (int i = 0; i < methods.length; i++) {
MethodGen me = new MethodGen(methods[i], method
.declaringClass().getSignature(), ce.getConstantPool());// TODO
if (me.getName().equals(name)
&& me.getSignature().equals(signature)) {
// The call to editMethod should have already handled
// the methodEditors mapping, but we still need to do
// methodInfos.
return (me);
}
// release(methods[i], ce.getClassName());
}
} catch (ClassNotFoundException ex1) {
} catch (ClassFormatException ex2) {
}
throw new NoSuchMethodException(method.toString());
}
public MethodGen editMethod(Method info, String declaringClass) {
// Groan, we have to do this the HARD way.
db("Creating a new MethodEditor for " + info.getName());
String name = info.getName();
String signature = info.getSignature();
try {
ClassGen ce = editClass(declaringClass);
Method[] methods = ce.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(name)
&& methods[i].getSignature().equals(signature)) {
MethodGen me = new MethodGen(methods[i], declaringClass, ce
.getConstantPool());
// The call to editMethod should have already handled
// the methodEditors mapping, but we still need to do
// methodInfos.
return (me);
}
// release(methods[i], ce.getClassName());
}
} catch (ClassNotFoundException ex1) {
} catch (ClassFormatException ex2) {
}
return null;
// throw new NoSuchMethodException(info.toString());
}
public FieldGen editField(MemberRef field) throws NoSuchFieldException {
// Just like we had to do with methods
NameAndType nat = field.nameAndType();
String name = nat.name();
Type type = nat.type();
try {
ClassGen ce = editClass(field.declaringClass());
Field[] fields = ce.getFields();
for (int i = 0; i < fields.length; i++) {
FieldGen fe = editField(fields[i], field.declaringClass()
.getSignature());// TODO
if (fe.getName().equals(name) && fe.getType().equals(type)) {
return (fe);
}
}
} catch (ClassNotFoundException ex1) {
} catch (ClassFormatException ex2) {
}
return null;
// throw new NoSuchFieldException(field.toString());
}
public FieldGen editField(Field info, String className) {
// Check the cache
String name = info.getName();
Type type = info.getType();
try {
ClassGen ce = editClass(className);
Field[] fields = ce.getFields();
for (int i = 0; i < fields.length; i++) {
FieldGen fe = editField(fields[i], className);
if (fe.getName().equals(name) && fe.getType().equals(type)) {
return (fe);
}
}
} catch (ClassNotFoundException ex1) {
} catch (ClassFormatException ex2) {
}
return null;
// throw new NoSuchFieldException(info.toString());
}
public void release(JavaClass info) {
// Since we keep around all data, do nothing
}
public void release(ClassGen ce) {
// Since we keep around all data, do nothing
}
public void release(Method info, String className) {
// Since we keep around all data, do nothing
}
public void release(Field info, String className) {
// Since we keep around all data, do nothing
}
/**
* Classes that are ignored are not committed.
*
* @see ignoreClass
*/
public void commit(JavaClass info) {
ClassGen cg = (ClassGen) classEditors.get(info.getClassName());
JavaClass jc = (JavaClass) cg.getJavaClass();
classInfos.put(info.getClassName(), jc);
}
public void commit(ClassGen info) {
classEditors.put(info.getClassName(), info);
}
public void commit(MethodGen methodGen) {
this.commit(methodGen.getMethod(), methodGen.getClassName());
}
public void commit(Method m, String classname) {
try {
ClassGen cg = editClass(classname);
Method oldMethod = cg.containsMethod(m.getName(), m.getSignature());
cg.replaceMethod(oldMethod, m);
} catch (ClassNotFoundException cnfe) {
// IF THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T
// HAPPEN
}
}
/*
* private Method commit(Method m){ try{ ClassGen cg = editClass(classname);
* Method oldMethod = cg.containsMethod(m.getName(),m.getSignature());
* cg.replaceMethod(oldMethod, m); }catch(ClassNotFoundException cnfe){ //IF
* THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T HAPPEN } }
*/
public void commit(Field f, String classname) {
try {
ClassGen cg = editClass(classname); // Ask to commit the ClassGen
Field oldField = cg.containsField(f.getName());
cg.replaceField(oldField, f);
} catch (ClassNotFoundException cnfe) {
// IF THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T
// HAPPEN
}
}
/*
* private Field commit(Field f){ FieldGen fg =
* (FieldGen)fieldEditors.get(f); if(fg != null){ fg.update(); Field
* newField = fg.getField(); //return final version of fg
* fieldEditors.remove(f); fieldEditors.put(newField, fg); return newField;
* }else{ return f; //return the old field } }
*/
// THE COMMIT OF A METHOD/FIELD SHOULD RESULT IN THE COMMIT OF THE
// PARENT
// CLASS SO commit(JavaClass) SHOULD SUFFICE.
// Reason I got rid of commit(method) is bcel's Method has no mapping to
// the class that the method belongs to. Each editField or editMethod
// ensures that the class is loaded. (release does nothing)
public void commit() {
}
public void commitDirty() {
}
/*
* // Commit all dirty fields Object[] array =
* this.fieldEditors.values().toArray(); for(int i = 0; i < array.length;
* i++) { FieldEditor fe = (FieldEditor) array[i]; if(fe.isDirty() &&
* !ignoreField(fe.memberRef())) { comm(" Committing field: " +
* fe.declaringClass().name() + "." + fe.name()); commit(fe.fieldInfo()); } } //
* Commit all dirty methods array = this.methodEditors.values().toArray();
* for(int i = 0; i < array.length; i++) { MethodEditor me = (MethodEditor)
* array[i]; if(me.isDirty() && !ignoreMethod(me.memberRef())) { comm("
* Committing method: " + me.declaringClass().name() + "." + me.name() +
* me.type()); commit(me.methodInfo()); } } // Commit all dirty classes
* array = this.classEditors.values().toArray(); for(int i = 0; i <
* array.length; i++) { ClassEditor ce = (ClassEditor) array[i];
* if(ce.isDirty() && !ignoreClass(ce.type())) { comm(" Committing class: " +
* ce.name()); commit(ce.classInfo()); } } }
*/
}

@ -0,0 +1,17 @@
<html>
<body>
<p>Repositories for important BLOAT objects such as the
<tt>Editor</tt>, <tt>ClassHierarchy</tt>, and <tt>FlowGraph</tt>s. In
order to avoid build dependencies with other packages we took the
novel approach of having a "context" interface in several packages that
the classes in this package then implement.</p>
<p>The reason we implement all of the methods in one class is so that
if the user wants to have different contexts with different attributes
(for instance, caching policies), all one has to do is subclass
<tt>BloatContext</tt> instead of subclassing other contextes which may
become ackward.</p>
</body>
</html>

@ -0,0 +1,537 @@
/*
* Class: InductionVarAnalyzer
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
/* Demand-driven Induction Variable Analysis (diva)*/
package edu.purdue.cs.bloat.diva;
import java.util.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.ssa.ComponentVisitor;
import edu.purdue.cs.bloat.ssa.SSAGraph;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.IfCmpStmt;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MemExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.SCStmt;
import edu.purdue.cs.bloat.tree.SRStmt;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.Swizzler;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
/**
* InductionVarAnalyzer traverses a control flow graph and looks for array
* element swizzle operations inside loops. If possible, these swizzle
* operations are hoisted out of the loop and are replaced with range swizzle
* operations. The technique used is Demand-driven Induction Variable Analysis
* (DIVA).
* <p>
* To accomplish its tasks, InductionVarAnalyzer keeps track of a number of
* induction variables (represented by Swizzler objects) and local variables.
*
* @see Swizzler
* @see LocalExpr
*/
public class InductionVarAnalyzer implements Optimization {
public static boolean DEBUG = false;
SSAGraph ssaGraph;
FlowGraph CFG; // Control flow graph being operated on
LinkedHashMap IndStore; // Stores induction variables and
// associated swizzlers
LinkedHashMap LocalStore; // Stores local variables
Expr ind_var = null; // An induction variable
Expr ind_init = null; // Initial value of an induction variable
Expr ind_term = null; // Not used???
Expr ind_inc = null; // Expression used to increment induction
// variable (all uses commented out)
Expr tgt = null; // Target of the phi statement that defines
// an induction var
boolean changed = false; // Was the cfg changed?
/**
* Searches the list of induction variables for an induction variable with a
* given value number.
*
* @param vn
* Value number to search for.
*
* @return Swizzler object whose target has the desired value number or
* null, if value number is not found.
*/
public Swizzler getSwizzler(int vn) {
Iterator iter = IndStore.values().iterator();
while (iter.hasNext()) {
Swizzler swz = (Swizzler) iter.next();
if ((swz.target().valueNumber() == vn)
|| (swz.ind_var().valueNumber() == vn))
return swz;
}
return null;
}
/**
* Searchs the stored list of local variables for a local variable with a
* given value number.
*
* @param vn
* The value number to search for.
*
* @return The local variable with the given value number, or null, if not
* found.
*/
public MemExpr getLocal(int vn) {
Iterator iter = LocalStore.keySet().iterator();
while (iter.hasNext()) {
MemExpr le = (MemExpr) iter.next();
if (le.valueNumber() == vn)
return le;
}
return null;
}
/**
* Displays (to System.out) all of the Swizzlers stored in the induction
* variable store.
*
* @see Swizzler
*/
public void Display_store() {
Iterator iter = IndStore.values().iterator();
while (iter.hasNext()) {
Swizzler indswz = (Swizzler) iter.next();
System.out.println("\nIV: " + indswz.ind_var() + " tgt: "
+ indswz.target() + "\narray: " + indswz.array()
+ " init: " + indswz.init_val() + " end: "
+ indswz.end_val());
}
}
/**
* Displays the contents of a Swizzler object to System.out.
*
* @param indswz
* The Swizzler to display.
*/
public void displaySwizzler(Swizzler indswz) {
System.out.println("\nIV: " + indswz.ind_var() + "vn:"
+ indswz.ind_var().valueNumber() + " tgt: " + indswz.target()
+ "vn:" + indswz.target().valueNumber() + "\narray: "
+ indswz.array() + " init: " + indswz.init_val() + " end: "
+ indswz.end_val());
}
/**
* Adds a swizzle range statement (SRStmt) to the end of each predecessor
* block of the block containing the phi statement that defines an induction
* variable provided that the phi block does not dominate its predacessor.
* Phew.
*
* @param indswz
* Swizzler representing the induction variable on which the
* range swizzle statement is added.
*/
public void insert_aswrange(Swizzler indswz) {
Iterator iter = CFG.preds(indswz.phi_block()).iterator();
while (iter.hasNext()) {
Block blk = (Block) iter.next();
if (!indswz.phi_block().dominates(blk)) {
SRStmt aswrange = new SRStmt((Expr) indswz.array().clone(),
(Expr) indswz.init_val().clone(), (Expr) indswz
.end_val().clone());
blk.tree().addStmtBeforeJump(aswrange);
changed = true;
if (DEBUG) {
System.out.println("Inserted ASWR: " + aswrange
+ "\nin block: " + blk);
System.out.println("$$$ can insert aswrange now\n"
+ "array: " + indswz.array() + "\nIV: "
+ indswz.ind_var() + "\ninit: " + indswz.init_val()
+ "\nend: " + indswz.end_val());
}
}
}
}
/* To determine if a phi statement is a mu */
/* Returns null if not a MU and sets ind_var & ind_init */
/* to refer to the IV & its initial value otherwise */
/**
* Determines whether or not a phi statement is a mu function. A mu function
* is a phi function that merges values at loop headers, as opposed to those
* that occur as a result of forward branching. Mu functions always have two
* arguments.
*
* @param phi
* phi statement that may be a mu function
* @param cfg
* CFG to look through <font color="ff0000">Get rid of this
* parameter</font>
*
* @return The block containing the mu functions external (that is, outside
* the loop) argument, also known as the external ssalink. If the
* phi statement is not a mu function, null is returned.
*/
public Block isMu(PhiJoinStmt phi, FlowGraph cfg) {
// Does it contain two operands?
if (phi.numOperands() != 2)
return null;
// Is it REDUCIBLE?
if (cfg.blockType(phi.block()) == Block.IRREDUCIBLE
|| cfg.blockType(phi.block()) == Block.NON_HEADER) {
return null;
}
/*
* Does one of them dominate the phi and the other dominated by the phi?
*/
Iterator iter = cfg.preds(phi.block()).iterator();
Block pred1 = (Block) iter.next();
Block pred2 = (Block) iter.next();
if (pred1.dominates(phi.block()) && phi.block().dominates(pred2)
&& (pred1 != phi.block())) {
if (DEBUG)
System.out.println("Extlink = 1 pred1:" + pred1 + " pred2:"
+ pred2);
ind_var = phi.operandAt(pred2);
ind_init = phi.operandAt(pred1);
return pred1;
}
if (pred2.dominates(phi.block()) && phi.block().dominates(pred1)
&& (pred2 != phi.block())) {
if (DEBUG)
System.out.println("Extlink = 2 pred1:" + pred1 + " pred2:"
+ pred2);
ind_var = phi.operandAt(pred1);
ind_init = phi.operandAt(pred2);
return pred2;
}
return null;
}
/**
* Performs DIVA on a CFG public static void transform(FlowGraph cfg) { //
* Create a new instance to allow multiple threads. InductionVarAnalyzer me =
* new InductionVarAnalyzer(); me.transform(cfg); }
*/
public void transform(MethodState state) {
transform(state.controlFlowGraph());
}
/**
* Performs DIVA on a CFG.
*/
private void transform(FlowGraph cfg) {
ssaGraph = new SSAGraph(cfg);
CFG = cfg;
IndStore = new LinkedHashMap();
LocalStore = new LinkedHashMap();
changed = false;
if (DEBUG) {
System.out
.println("----------Before visitComponents--------------");
cfg.print(System.out);
}
// Visit each strongly connected component (SCC) in the CFG. SCCs
// correspond to sequences in the program. Visit each node in the
// SCC and build the local variable store. Create Swizzlers at
// PhiStmts, if approproate, and store them in the induction
// variable store. If it can be determined that an array element
// swizzle can be hoisted out of a loop, it is hoisted.
ssaGraph.visitComponents(new ComponentVisitor() {
public void visitComponent(List scc) {
if (DEBUG)
System.out.println("SCC =");
Iterator e = scc.iterator();
while (e.hasNext()) {
Node v = (Node) e.next();
if (DEBUG)
System.out.println(" " + v + "{" + v.key() + "} "
+ v.getClass());
v.visit(new TreeVisitor() {
public void visitPhiJoinStmt(PhiJoinStmt phi) {
if (isMu(phi, CFG) != null) {
// Iterator iter = phi.operands().iterator();
tgt = phi.target();
if (DEBUG)
System.out.println("IV:" + ind_var + " VN:"
+ ind_var.valueNumber() + "\ninit:"
+ ind_init + " target: " + tgt
+ " VN: " + tgt.valueNumber());
Swizzler swz = new Swizzler(ind_var, tgt,
ind_init, phi.block());
if (DEBUG) {
System.out
.println("store swizzler for "
+ ind_var.def() + " & "
+ tgt.def());
displaySwizzler(swz);
}
if (ind_var.def() != null)
IndStore.put(ind_var.def(), swz);
if (tgt.def() != null)
IndStore.put(tgt.def(), swz);
if (DEBUG)
System.out.println(" Mu: " + phi + "{"
+ phi.key() + "}");
} else {
if (DEBUG)
System.out.println("Phi: " + phi + "{"
+ phi.key() + "}");
}
}
public void visitLocalExpr(LocalExpr me) {
if (me.def() != null) {
if (LocalStore.get(me.def()) == null) {
LocalStore.put(me.def(), me);
}
}
if (LocalStore.get(me) == null) {
LocalStore.put(me, me);
}
if (DEBUG)
System.out.println("stored ME: " + me
+ " vn: " + me.valueNumber());
}
public void visitStaticFieldExpr(StaticFieldExpr me) {
if (me.def() != null) {
if (LocalStore.get(me.def()) == null) {
LocalStore.put(me.def(), me);
}
}
if (LocalStore.get(me) == null) {
LocalStore.put(me, me);
}
if (DEBUG)
System.out.println("stored ME: " + me
+ " vn: " + me.valueNumber());
}
public void visitIfCmpStmt(IfCmpStmt cmp) {
Swizzler indswz = null;
boolean set_term = false;
if (cmp.left().def() != null)
indswz = (Swizzler) IndStore.get(cmp.left()
.def());
if (indswz != null) {
if (DEBUG)
displaySwizzler(indswz);
if (indswz.end_val() == null) {
indswz.set_end_val(cmp.right());
set_term = true;
if (DEBUG)
System.out.println("Set end_val of "
+ indswz.ind_var() + " to "
+ cmp.right());
}
} else {
if (cmp.right().def() != null)
indswz = (Swizzler) IndStore.get(cmp
.right().def());
if (indswz != null) {
if (DEBUG)
displaySwizzler(indswz);
if (indswz.end_val() == null) {
indswz.set_end_val(cmp.left());
set_term = true;
if (DEBUG)
System.out
.println("Set end_val of "
+ indswz.ind_var()
+ " to "
+ cmp.left());
}
}
}
if (set_term && indswz != null
&& indswz.array() != null) {
indswz.aswizzle().set_redundant(true);
insert_aswrange(indswz);
}
}
public void visitSCStmt(SCStmt sc) {
Swizzler indswz;
MemExpr le = null;
if (DEBUG)
System.out.println("SC: array= " + sc.array()
+ " VN:" + sc.array().valueNumber()
+ "\nindex=" + sc.index() + " VN:"
+ sc.index().valueNumber());
indswz = getSwizzler(sc.index().valueNumber());
if (indswz != null) {
if (DEBUG)
displaySwizzler(indswz);
if (indswz.array() == null) {
le = getLocal(sc.array().valueNumber());
if (le == null && sc.array().def() != null)
le = getLocal(sc.array().def()
.valueNumber());
if (le != null) {
if (DEBUG)
System.out.println("Le: " + le);
indswz.set_array(le);
indswz.set_aswizzle(sc);
} else
return;
}
if (indswz.end_val() != null) {
sc.set_redundant(true);
insert_aswrange(indswz);
}
}
}
/*
* public void visitStoreExpr(StoreExpr ind_store) {
* if(ind_var != null) {
* if(ind_var.equalsExpr(ind_store.target())) { if (tgt !=
* null && ind_store.expr() instanceof ArithExpr){
* ArithExpr ind_exp = (ArithExpr)ind_store.expr();
* if(tgt.equalsExpr(ind_exp.left())) ind_inc =
* ind_exp.right(); else if(tgt.equals(ind_exp.right()))
* ind_inc = ind_exp.left(); else { ind_inc = null;
* return; } System.out.println("Ind_inc: "+ind_inc); } } } }
*/
});
}
}
});
if (DEBUG) {
System.out.println("------------After visitComponents---------");
cfg.print(System.out);
}
// If the CFG changed (i.e. if an array range swizzle was added),
// traverse
// the graph and remove redundent swizzle statements.
if (changed) {
cfg.visit(new TreeVisitor() {
ListIterator iter;
public void visitTree(Tree tree) {
iter = tree.stmts().listIterator();
while (iter.hasNext()) {
Stmt stmt = (Stmt) iter.next();
stmt.visit(this);
}
}
public void visitSCStmt(SCStmt sc) {
Object dup2stmt;
if (sc.redundant()) {
iter.remove();
dup2stmt = iter.previous();
iter.remove();
if (DEBUG)
System.out.println("Removed Redundant ASW: " + sc
+ "\nand " + dup2stmt);
}
}
});
}
if (DEBUG) {
System.out.println("----------------After cfg.visit--------------");
cfg.print(System.out);
}
}
public String traceMessage(String dateString) {
return " DIVA: " + dateString;
}
public String preDebugMessage() {
return "-----Before DIVA------";
}
public String postDebugMessage() {
return "-----After DIVA-----";
}
}

@ -0,0 +1,25 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
InductionVarAnalyzer.class\
include ../class.mk

@ -0,0 +1,8 @@
<html>
<body>
<p>Performs demand-driven induction variable analysis on a Java
classfile.</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,179 @@
/*
* Class: EditorContext
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
/**
* An <tt>EditorContext</tt> supplies a means of loading and editing classes.
* Note that a number of these methods are identical to methods in
* <tt>Editor</tt>. It is expected that an <tt>EditorContext</tt> will have
* a different caching (of <tt>ClassEditor</tt>s, etc.) policy than
* <tt>Editor</tt> does. Hence, the methods in <tt>EditorContext</tt> should
* be used to edit classes, etc.
*/
public interface EditorContext {
/**
* Loads a class into BLOAT
*/
public JavaClass loadClass(String className) throws ClassNotFoundException;
/**
* Creates a new <code>ClassInfo</code>
*
* @param modifiers
* The modifiers describing the newly-created class
* @param classIndex
* The index of the name of the newly-created class in its
* constant pool
* @param superClassIndex
* The index of the name of the newly-created class's superclass
* in its constant pool
* @param interfaceIndexes
* The indexes of the names of the interfaces that the
* newly-created class implements
* @param constants
* The constant pool for the newly created class (a list of
* {@link Constant}s).
*/
/**
* Returns the <tt>ClassHierarchy</tt> of all classes and interfaces known
* to BLOAT.
*/
public ClassHierarchy getHierarchy();
public JavaClass newClassInfo(int class_name_index,
int superclass_name_index, String file_name, int major, int minor,
int access_flags, ConstantPool constant_pool, int[] interfaces,
Field[] fields, Method[] methods, Attribute[] attributes);
/**
* Returns a <code>ClassEditor</code> for editing a new class with the
* given name. It will override any class with the given name that is
* already being edited.
*/
public ClassGen newClass(int accessflags, String className,
String file_name, Type superType, Type[] interfaces);
/**
* Returns a <tt>ClassEditor</tt> used to edit a class of a given name.
*/
public ClassGen editClass(String className) throws ClassNotFoundException,
ClassFormatException;
/**
* Returns a <tt>ClassEditor</tt> used to edit a class described by a
* given <tt>Type</tt>.
*/
public ClassGen editClass(Type classType) throws ClassNotFoundException,
ClassFormatException;
/**
* Returns a <tt>ClassEditor</tt> used to edit a class described by a
* given <tt>ClassInfo</tt>.
*/
public ClassGen editClass(JavaClass info);
/**
* Returns a <tt>FieldEditor</tt> for editing a <tt>FieldInfo</tt>.
*/
public FieldGen editField(Field info, String classname);
/**
* Returns a <tt>FieldEditor</tt> for editing a field.
*/
public FieldGen editField(MemberRef field) throws NoSuchFieldException;
/**
* Returns a <tt>MethodEditor</tt> for editing a method.
*/
public MethodGen editMethod(Method info, String classname);
/**
* Returns a <tt>MethodEditor</tt> for editing a method.
*/
public MethodGen editMethod(MethodRef method) throws NoSuchMethodException;
/**
* Signals that we are done editing a method. The object used to model it
* may be reclaimed.
*/
public void release(Method info, String className);
/**
* Signals that we are done editing a field. The object used to model it may
* be reclaimed.
*/
public void release(Field info, String className);
/**
* Signals that we are done editing a class. The object used to model it may
* be reclaimed.
*/
public void release(JavaClass info);
/**
* Commits the changes made to a class.
*/
public void commit(JavaClass info);
/**
* Commits the changes made to a method.
*/
public void commit(Method info, String className);
/**
* Commits the changes made to a method.
*/
public void commit(MethodGen info);
/**
* Commits the changes made to a field.
*/
public void commit(Field info, String className);
/**
* Commits all changes made to classes, methods, and fields.
*/
public void commit();
}

@ -0,0 +1,480 @@
/*
* Class: InstructionAdaptor
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.*;
/**
* This adapter provides a default implementation for every method in
* InstructionVisitor.
*/
public class InstructionAdapter {
public void visit_nop(Instruction inst) {
}
public void visit_ldc(Instruction inst) {
}
public void visit_iload(Instruction inst) {
}
public void visit_lload(Instruction inst) {
}
public void visit_fload(Instruction inst) {
}
public void visit_dload(Instruction inst) {
}
public void visit_aload(Instruction inst) {
}
public void visit_iaload(Instruction inst) {
}
public void visit_laload(Instruction inst) {
}
public void visit_faload(Instruction inst) {
}
public void visit_daload(Instruction inst) {
}
public void visit_aaload(Instruction inst) {
}
public void visit_baload(Instruction inst) {
}
public void visit_caload(Instruction inst) {
}
public void visit_saload(Instruction inst) {
}
public void visit_istore(Instruction inst) {
}
public void visit_lstore(Instruction inst) {
}
public void visit_fstore(Instruction inst) {
}
public void visit_dstore(Instruction inst) {
}
public void visit_astore(Instruction inst) {
}
public void visit_iastore(Instruction inst) {
}
public void visit_lastore(Instruction inst) {
}
public void visit_fastore(Instruction inst) {
}
public void visit_dastore(Instruction inst) {
}
public void visit_aastore(Instruction inst) {
}
public void visit_bastore(Instruction inst) {
}
public void visit_castore(Instruction inst) {
}
public void visit_sastore(Instruction inst) {
}
public void visit_pop(Instruction inst) {
}
public void visit_pop2(Instruction inst) {
}
public void visit_dup(Instruction inst) {
}
public void visit_dup_x1(Instruction inst) {
}
public void visit_dup_x2(Instruction inst) {
}
public void visit_dup2(Instruction inst) {
}
public void visit_dup2_x1(Instruction inst) {
}
public void visit_dup2_x2(Instruction inst) {
}
public void visit_swap(Instruction inst) {
}
public void visit_iadd(Instruction inst) {
}
public void visit_ladd(Instruction inst) {
}
public void visit_fadd(Instruction inst) {
}
public void visit_dadd(Instruction inst) {
}
public void visit_isub(Instruction inst) {
}
public void visit_lsub(Instruction inst) {
}
public void visit_fsub(Instruction inst) {
}
public void visit_dsub(Instruction inst) {
}
public void visit_imul(Instruction inst) {
}
public void visit_lmul(Instruction inst) {
}
public void visit_fmul(Instruction inst) {
}
public void visit_dmul(Instruction inst) {
}
public void visit_idiv(Instruction inst) {
}
public void visit_ldiv(Instruction inst) {
}
public void visit_fdiv(Instruction inst) {
}
public void visit_ddiv(Instruction inst) {
}
public void visit_irem(Instruction inst) {
}
public void visit_lrem(Instruction inst) {
}
public void visit_frem(Instruction inst) {
}
public void visit_drem(Instruction inst) {
}
public void visit_ineg(Instruction inst) {
}
public void visit_lneg(Instruction inst) {
}
public void visit_fneg(Instruction inst) {
}
public void visit_dneg(Instruction inst) {
}
public void visit_ishl(Instruction inst) {
}
public void visit_lshl(Instruction inst) {
}
public void visit_ishr(Instruction inst) {
}
public void visit_lshr(Instruction inst) {
}
public void visit_iushr(Instruction inst) {
}
public void visit_lushr(Instruction inst) {
}
public void visit_iand(Instruction inst) {
}
public void visit_land(Instruction inst) {
}
public void visit_ior(Instruction inst) {
}
public void visit_lor(Instruction inst) {
}
public void visit_ixor(Instruction inst) {
}
public void visit_lxor(Instruction inst) {
}
public void visit_iinc(Instruction inst) {
}
public void visit_i2l(Instruction inst) {
}
public void visit_i2f(Instruction inst) {
}
public void visit_i2d(Instruction inst) {
}
public void visit_l2i(Instruction inst) {
}
public void visit_l2f(Instruction inst) {
}
public void visit_l2d(Instruction inst) {
}
public void visit_f2i(Instruction inst) {
}
public void visit_f2l(Instruction inst) {
}
public void visit_f2d(Instruction inst) {
}
public void visit_d2i(Instruction inst) {
}
public void visit_d2l(Instruction inst) {
}
public void visit_d2f(Instruction inst) {
}
public void visit_i2b(Instruction inst) {
}
public void visit_i2c(Instruction inst) {
}
public void visit_i2s(Instruction inst) {
}
public void visit_lcmp(Instruction inst) {
}
public void visit_fcmpl(Instruction inst) {
}
public void visit_fcmpg(Instruction inst) {
}
public void visit_dcmpl(Instruction inst) {
}
public void visit_dcmpg(Instruction inst) {
}
public void visit_ifeq(Instruction inst) {
}
public void visit_ifne(Instruction inst) {
}
public void visit_iflt(Instruction inst) {
}
public void visit_ifge(Instruction inst) {
}
public void visit_ifgt(Instruction inst) {
}
public void visit_ifle(Instruction inst) {
}
public void visit_if_icmpeq(Instruction inst) {
}
public void visit_if_icmpne(Instruction inst) {
}
public void visit_if_icmplt(Instruction inst) {
}
public void visit_if_icmpge(Instruction inst) {
}
public void visit_if_icmpgt(Instruction inst) {
}
public void visit_if_icmple(Instruction inst) {
}
public void visit_if_acmpeq(Instruction inst) {
}
public void visit_if_acmpne(Instruction inst) {
}
public void visit_goto(Instruction inst) {
}
public void visit_jsr(Instruction inst) {
}
public void visit_ret(Instruction inst) {
}
public void visit_switch(Instruction inst) {
}
public void visit_ireturn(Instruction inst) {
}
public void visit_lreturn(Instruction inst) {
}
public void visit_freturn(Instruction inst) {
}
public void visit_dreturn(Instruction inst) {
}
public void visit_areturn(Instruction inst) {
}
public void visit_return(Instruction inst) {
}
public void visit_getstatic(Instruction inst) {
}
public void visit_putstatic(Instruction inst) {
}
public void visit_putstatic_nowb(Instruction inst) {
}
public void visit_getfield(Instruction inst) {
}
public void visit_putfield(Instruction inst) {
}
public void visit_putfield_nowb(Instruction inst) {
}
public void visit_invokevirtual(Instruction inst) {
}
public void visit_invokespecial(Instruction inst) {
}
public void visit_invokestatic(Instruction inst) {
}
public void visit_invokeinterface(Instruction inst) {
}
public void visit_new(Instruction inst) {
}
public void visit_newarray(Instruction inst) {
}
public void visit_arraylength(Instruction inst) {
}
public void visit_athrow(Instruction inst) {
}
public void visit_checkcast(Instruction inst) {
}
public void visit_instanceof(Instruction inst) {
}
public void visit_monitorenter(Instruction inst) {
}
public void visit_monitorexit(Instruction inst) {
}
public void visit_multianewarray(Instruction inst) {
}
public void visit_ifnull(Instruction inst) {
}
public void visit_ifnonnull(Instruction inst) {
}
public void visit_rc(Instruction inst) {
}
public void visit_aupdate(Instruction inst) {
}
public void visit_supdate(Instruction inst) {
}
public void visit_aswizzle(Instruction inst) {
}
public void visit_aswrange(Instruction inst) {
}
}

@ -0,0 +1,70 @@
/*
* Class: InstructionVisitor
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.Instruction;
/**
* The visitor pattern allows functionality to be added to a number of classes
* (or in this case one class, <tt>Instruction</tt>, that can vary in
* behavior) without modifying the classes themselves. Additionally, the visitor
* pattern simulates double dispatching. For instance <tt>visit</tt> method of
* <tt>Instruction</tt> calls a particular method of
* <tt>InstructionVisitor</tt> based on the <tt>Instruction</tt>'s opcode.
* <p>
* <tt>InstructionVisitor</tt> provides an interface for performing actions
* based on the instruction type. Classes implementing this interface should not
* be able to miss any of the instruction types. This interface was created as
* an alternative to having 138 different subtypes of Instruction.
*
* @see Instruction#visit
* @see edu.purdue.cs.bloat.tree.Tree
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*/
public interface InstructionVisitor {
public void visitInst(Instruction inst);
// public void visit_rc(Instruction inst);
// public void visit_aupdate(Instruction inst);
// public void visit_supdate(Instruction inst);
// public void visit_aswizzle(Instruction inst);
// public void visit_aswrange(Instruction inst);
}

@ -0,0 +1,31 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
ClassHierarchy.class\
EditorContext.class\
InstructionAdapter.class\
InstructionVisitor.class\
MemberRef.class\
MethodRef.class\
NameAndType.class\
include ../class.mk

@ -0,0 +1,143 @@
/*
* Class: MemberRef
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.*;
/**
* MemberRef represents a method or field (as a <tt>NameAndType</tt>) and the
* class (as a <tt>Type</tt>) in which it is declared.
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*
* I found it rather confusing having MemberRef refer to both fields and methods
* so I have subclassed MemberRef with MethodRef for use when refering to
* methods. --Arrin
* @see MethodRef
*/
public class MemberRef {
private final ReferenceType declaringClass;
private final NameAndType nameAndType;
/**
* Constructor.
*
* @param declaringClass
* The type of the class which declared the member.
* @param nameAndType
* The name and type of the member.
*/
public MemberRef(ReferenceType declaringClass, NameAndType nameAndType) {
this.declaringClass = declaringClass;
this.nameAndType = nameAndType;
}
/**
* Get the type of the class which declared the member.
*
* @return The type of the class which declared the member.
*/
public ReferenceType declaringClass() {
return declaringClass;
}
/**
* Get the name of the member.
*
* @return The name of the member.
*/
public String name() {
return nameAndType.name();
}
/**
* Get the type of the member.
*
* @return The type of the member.
*/
public Type type() {
return nameAndType.type();
}
/**
* Get the name and type of the member.
*
* @return The name and type of the member.
*/
public NameAndType nameAndType() {
return nameAndType;
}
/**
* Convert the reference to a string.
*
* @return A string representation of the reference.
*/
public String toString() {
// Take advantage of PRINT_TRUNCATED in Type
String className = declaringClass.toString();
return "<" + "Field" + " " + className + "." + name() + " " + type()
+ ">";
}
/**
* Check if an object is equal to this reference.
*
* @param obj
* The object to compare against.
* @return true if equal, false if not.
*/
public boolean equals(Object obj) {
return obj instanceof MemberRef
&& ((MemberRef) obj).declaringClass.equals(declaringClass)
&& ((MemberRef) obj).nameAndType.equals(nameAndType);
}
/**
* Hash the member reference.
*
* @return The hash code.
*/
public int hashCode() {
return declaringClass.hashCode() ^ nameAndType.hashCode();
}
}

@ -0,0 +1,117 @@
/*
* Class: MethodRef
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.*;
/**
* MemberRef represents a method or field (as a <tt>NameAndType</tt>) and the
* class (as a <tt>Type</tt>) in which it is declared.
*
* @author Arrin Daley (<a
* href="mailto:arrin@cs.anu.edu.au">arrin@cs.anu.edu.au</a>)
*
* I found it rather confusing having MemberRef refer to both fields and methods
* so I have subclassed MemberRef with MethodRef for use when refering to
* methods. --Arrin
* @see MemberRef
*/
/*
* BCEL types only refer to a field or object type but BLOAT types can refer to
* both a method and a field as a result I made this class to store Method
* reference information
*/
public class MethodRef extends MemberRef {
private final Type[] params;
private final Type returnType;
public MethodRef(ReferenceType declaringClass, NameAndType nameAndType,
Type returnType, Type[] paramTypes) {
super(declaringClass, nameAndType);
this.params = paramTypes;
this.returnType = returnType;
}
public Type[] paramTypes() {
return params;
}
public Type returnType() {
return returnType;
}
public Type type() {
return returnType;
}
public boolean equals(Object obj) {
if (super.equals(obj) && obj instanceof MethodRef) {
MethodRef methRef = (MethodRef) obj;
Type[] paramTest = methRef.paramTypes();
if (returnType.equals(methRef.returnType())
&& params.length == paramTest.length) {
for (int i = 0; i < params.length; i++) {
if (!params[i].equals(paramTest[i]))
return false;
}
} else {
return false;
}
} else
return false;
return true;
}
public String toString() {
// Take advantage of PRINT_TRUNCATED in Type
String className = declaringClass().toString();
return "<" + "Method" + " " + className + "." + name() + " "
+ Type.getMethodSignature(returnType, params) + ">";
}
public String getSignature() {
return Type.getMethodSignature(returnType, params);
}
}

@ -0,0 +1,112 @@
/*
* Class: NameAndType
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.editor;
import org.apache.bcel.generic.Type;
/**
* Methods and fields are described by their name and type descriptor.
* NameAndType represents exactly that.
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*
* In BLOAT NameAndType could refer to both Methods and Fields using MemberRef,
* Type being used to encapsulate the parameters and return type of the method.
* Types in BCEL can't do this so MethodRef is used for methods and MemberRef is
* used for fields. NameAndType is still used to refer to Methods but only
* encapsulates the name and return type of the method parameters are held
* inside MethodRef. --Arrin
*/
public class NameAndType {
private final String name;
private final Type type;
/**
* Constructor.
*/
public NameAndType(String name, Type type) {
this.name = name;
this.type = type;
}
/**
* Returns the name.
*/
public String name() {
return name;
}
/**
* Returns the type.
*/
public Type type() {
return type;
}
/**
* Returns a string representation of the name and type.
*/
public String toString() {
return "<NameandType " + name + " " + type + ">";
}
/**
* Check if an object is equal to this name and type.
*
* @param obj
* The object to compare against.
* @return <tt>true</tt> if equal
*/
public boolean equals(Object obj) {
return obj instanceof NameAndType
&& ((NameAndType) obj).name.equals(name)
&& ((NameAndType) obj).type.equals(type);
}
/**
* Returns a hash of the name and type.
*/
public int hashCode() {
return name.hashCode() ^ type.hashCode();
}
}

@ -0,0 +1,10 @@
<html>
<body>
<p>Allows classes, methods, and fields to be edited. In addition, the
representation of bytecodes (JVM instructions) is refined. Types,
opcodes, local variables, and special instrcution operands are
introduced.</p>
</body>
</html>

@ -0,0 +1,853 @@
/*
* Class: CallGraph
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.inline;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import edu.purdue.cs.bloat.editor.ClassHierarchy;
import edu.purdue.cs.bloat.editor.InstructionAdapter;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.editor.MethodRef;
import edu.purdue.cs.bloat.editor.NameAndType;
import edu.purdue.cs.bloat.util.Assert;
import java.io.*;
import java.util.*;
/**
* Grants access to certain information about a Java program. At least one root
* method must be specified. From these root methods, the call graph and
* information such as the classes that are instantiated during the Java program
* is computed.
*
* <p>
*
* The construction of the call graph is in the spirit of the "Program
* Virtual-call Graph" presented in [Bacon97]. However, certain changes have
* been made to tailor it to BLOAT and Java and to make the overall
* representation smaller.
*
* <p>
*
* Rapid type analysis is integrated into the construction of the call graph. A
* virtual method is not examined until we know that its declaring class has
* been instantiated.
*
* <p>
*
* Some classes are created internally by the VM and are missed by our analysis.
* So, we maintain a set of "pre-live" classes. We consider all of their
* constructors to be live.
*/
public class CallGraph {
public static boolean DEBUG = false;
private static Set preLive; // "Pre-live" classes
public static boolean USEPRELIVE = true;
public static boolean USE1_2 = true;
private Set roots; // Root methods (MethodRefs)
private Map calls; // Maps methods to the methods they
// call (virtual calls are not resolved)
private Set liveClasses; // Classes (Types) that have been instantiated
private Map resolvesTo; // Maps methods to the methods they resolve to
private Map blocked; // Maps types to methods blocked on those types
List worklist; // Methods to process
Set liveMethods; // Methods that may be executed
InlineContext context;
private ClassHierarchy hier;
static void db(String s) {
if (CallGraph.DEBUG)
System.out.println(s);
}
/**
* Initialize the set of classes that are "pre-live"
*/
private static void init() {
// We can't do this in the static initializer because USE1_2 might
// not have the desired value.
preLive = new LinkedHashSet();
preLive.add("java.lang.Boolean");
preLive.add("java.lang.Class");
preLive.add("java.lang.ClassLoader");
preLive.add("java.lang.Compiler");
preLive.add("java.lang.Integer");
preLive.add("java.lang.SecurityManager");
preLive.add("java.lang.String");
preLive.add("java.lang.StringBuffer");
preLive.add("java.lang.System");
preLive.add("java.lang.StackOverflowError");
preLive.add("java.lang.Thread");
preLive.add("java.lang.ThreadGroup");
preLive.add("java.io.BufferedInputStream");
preLive.add("java.io.BufferedReader");
preLive.add("java.io.BufferedOutputStream");
preLive.add("java.io.BufferedWriter");
preLive.add("java.io.File");
preLive.add("java.io.FileDescriptor");
preLive.add("java.io.InputStreamReader");
preLive.add("java.io.ObjectStreamClass");
preLive.add("java.io.OutputStreamWriter");
preLive.add("java.io.PrintStream");
preLive.add("java.io.PrintWriter");
preLive.add("java.net.URL");
preLive.add("java.security.Provider");
preLive.add("java.security.Security");
preLive.add("java.util.Hashtable");
preLive.add("java.util.ListResourceBundle");
preLive.add("java.util.Locale");
preLive.add("java.util.Properties");
preLive.add("java.util.Stack");
preLive.add("java.util.Vector");
preLive.add("java.util.zip.ZipFile");
// Some pre-live classes are only available on JDK1.2.
if (USE1_2) {
preLive.add("java.lang.Package");
preLive.add("java.lang.ref.Finalizer");
preLive.add("java.lang.ref.ReferenceQueue");
preLive.add("java.io.FilePermission");
preLive.add("java.io.UnixFileSystem");
preLive.add("java.net.URLClassLoader");
preLive.add("java.security.SecureClassLoader");
preLive.add("java.security.AccessController");
preLive.add("java.text.resources.LocaleElements");
preLive.add("java.text.resources.LocaleElements_en");
preLive.add("java.util.LinkedHashMap");
preLive.add("java.util.jar.JarFile");
}
}
/**
* Adds (the name of) a class to the set of classes that are considered to
* be "pre-live"
*/
public static void addPreLive(String name) {
if (preLive == null) {
init();
}
preLive.add(name);
}
/**
* Removes a class from the set of "pre-live" classes
*
* @return <tt>true</tt> if the class was "pre-live"
*/
public static boolean removePreLive(String name) {
if (preLive == null) {
init();
}
return (preLive.remove(name));
}
/**
* Constructor.
*
* @param context
* <Tt>InlineContext</tt> used to examine classes and methods.
*
* @param roots
* The methods (represented as <tt>MemberRef</tt>s) considered
* to the roots (that is, the "main" methods) of the call graph.
* Presumably, only static methods or constructors can be root
* methods.
*/
public CallGraph(InlineContext context, Set roots) {
Assert.isTrue(roots != null, "A call graph must have roots");
Assert.isTrue(roots.size() > 0, "A call graph must have roots");
if (preLive == null) {
init();
}
this.context = context;
this.hier = context.getHierarchy();
this.roots = roots;
this.liveClasses = new LinkedHashSet();
this.resolvesTo = new LinkedHashMap();
this.calls = new LinkedHashMap();
this.blocked = new LinkedHashMap();
this.worklist = new LinkedList(this.roots);
this.liveMethods = new LinkedHashSet();
// To save space, make one InstructionVisitor and use it on every
// Instruction.
CallVisitor visitor = new CallVisitor(this);
db("Adding pre-live classes");
doPreLive();
db("Constructing call graph");
// Examine each method in the worklist. At each constructor
// invocation make note of the type that was created. At each
// method call determine all possible methods that it can resolve
// to. Add the methods of classes that have been instantiated to
// the worklist.
while (!worklist.isEmpty()) {
MethodRef caller = (MethodRef) worklist.remove(0);
if (liveMethods.contains(caller)) {
// We've already handled this method
continue;
}
MethodGen callerMethod = null;
try {
callerMethod = context.editMethod(caller);
} catch (NoSuchMethodException ex1) {
System.err.println("** Could not find method: " + caller);
ex1.printStackTrace(System.err);
System.exit(1);
}
// If the method is abstract or native, we can't do anything
// with it.
if (callerMethod.isAbstract()) {
continue;
}
liveMethods.add(caller);
if (callerMethod.isNative()) {
// We still want native methods to be live
continue;
}
db("\n Examining method " + caller);
Set callees = new LinkedHashSet(); // Methods called by caller
calls.put(caller, callees);
// If the method is static or is a constructor, the classes
// static initializer method must have been called. Make note
// of this.
if (callerMethod.isStatic()
|| callerMethod.getName().equals("<init>")) {
addClinit(new ObjectType(callerMethod.getClassName()));
}
// Examine the instructions in the caller method.
Iterator code = callerMethod.getInstructionList().iterator();
visitor.setCaller(callerMethod);
while (code.hasNext()) {
InstructionHandle o = (InstructionHandle) code.next();
Instruction inst = o.getInstruction();
visitor.visit(inst, callerMethod.getConstantPool());
}
}
// We're done constructing the call graph. Try to free up some
// memory.
blocked = null;
}
/**
* Helper method to add the static initializers and all constructors of the
* pre-live classes to the worklist, etc.
*/
private void doPreLive() {
if (!USEPRELIVE) {
return;
}
db("Making constructors of pre-live classes live");
Iterator iter = preLive.iterator();
while (iter.hasNext()) {
String name = (String) iter.next();
db(" " + name + " is pre-live");
name = name.replace('.', '/');
ClassGen ce = null;
try {
ce = context.editClass(name);
} catch (ClassNotFoundException ex1) {
System.err.println("** Cannot find pre-live class: " + name);
ex1.printStackTrace(System.err);
System.exit(1);
}
// Make class and static initializer live
liveClasses.add(new ObjectType(ce.getClassName()));
addClinit(new ObjectType(ce.getClassName()));
// Make all constructors live
Method[] methods = ce.getMethods();
for (int i = 0; i < methods.length; i++) {
MethodGen method = context.editMethod(methods[i], ce
.getClassName());
if (method.getName().equals("<init>")) {
db(" " + method);
MethodRef methRef = new MethodRef(new ObjectType(ce
.getClassName()), new NameAndType(method.getName(),
method.getReturnType()), method.getReturnType(),
method.getArgumentTypes());
worklist.add(methRef);
}
}
}
}
/**
* Adds the static initializer for a given <tt>Type</tt> to the worklist.
*/
void addClinit(Type type) {
try {
ClassGen ce = context.editClass(type);
Method[] methods = ce.getMethods();
for (int i = 0; i < methods.length; i++) {
MethodGen clinit = context.editMethod(methods[i], ce
.getClassName());
if (clinit.getName().equals("<clinit>")) {
MethodRef methRef = new MethodRef(new ObjectType(ce
.getClassName()), new NameAndType(clinit.getName(),
clinit.getReturnType()), clinit.getReturnType(),
clinit.getArgumentTypes());
worklist.add(methRef);
context.release(clinit.getMethod(), ce.getClassName());
break;
}
context.release(clinit.getMethod(), ce.getClassName());
}
context.release(ce.getJavaClass());
} catch (ClassNotFoundException ex1) {
System.err.println("** Could not find class for " + type);
ex1.printStackTrace(System.err);
System.exit(1);
}
}
/**
* Handles a virtual call. Determines all possible methods the call could
* resolve to. Adds the method whose declaring classes are live to the
* worklist. Blocks the rest on their declaring types.
*/
void doVirtual(MethodGen caller, MethodRef callee) {
// Figure out which methods the callee can resolve to.
Iterator resolvesToWith = hier.resolvesToWith(callee).iterator();
while (resolvesToWith.hasNext()) {
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) resolvesToWith
.next();
db(" resolves to " + rtw.method);
// Add all possible non-abstract methods to the call graph.
// This way, when a blocked method becomes unblocked, it will
// still be in the call graph.
addCall(caller, rtw.method);
Iterator rTypes = rtw.rTypes.iterator();
boolean isLive = false; // Is one of the rTypes live?
while (rTypes.hasNext()) {
Type rType = (Type) rTypes.next();
if (liveClasses.contains(rType)) {
isLive = true;
db(" Method " + rtw.method + " is live");
worklist.add(rtw.method);
break;
}
}
if (!isLive) {
// If none of the receiver types is live, then the method is
// blocked on all possible receiver types.
rTypes = rtw.rTypes.iterator();
StringBuffer sb = new StringBuffer();
while (rTypes.hasNext()) {
Type rType = (Type) rTypes.next();
Set blockedMethods = (Set) blocked.get(rType);
if (blockedMethods == null) {
blockedMethods = new LinkedHashSet();
blocked.put(rType, blockedMethods);
}
blockedMethods.add(rtw.method);
sb.append(rType.toString());
if (rTypes.hasNext()) {
sb.append(',');
}
}
db(" Blocked " + rtw.method + " on " + sb);
}
}
}
/**
* Makes note of one method calling another. This does not make the method
* live.
*/
void addCall(MethodGen callerMethod, MethodRef callee) {
// Just maintain the calls mapping
MethodRef caller = new MethodRef(new ObjectType(callerMethod
.getClassName()), new NameAndType(callerMethod.getName(),
callerMethod.getReturnType()), callerMethod.getReturnType(),
callerMethod.getArgumentTypes());
Set callees = (Set) this.calls.get(caller);
if (callees == null) {
callees = new LinkedHashSet();
this.calls.put(caller, callees);
}
callees.add(callee);
}
/**
* Marks a <tt>Type</tt> as being lives. It also unblocks any methods that
* were blocked on the type.
*/
void makeLive(Type type) {
if (this.liveClasses.contains(type)) {
return;
}
// Make type live and unblock all methods blocked on it
db(" Making " + type + " live");
liveClasses.add(type);
Set blockedMethods = (Set) blocked.remove(type);
if (blockedMethods != null) {
Iterator iter = blockedMethods.iterator();
while (iter.hasNext()) {
MemberRef method = (MemberRef) iter.next();
db(" Unblocking " + method);
worklist.add(method);
}
}
}
/**
* Returns the methods (<tt>MemberRef</tt>s) to which a given method
* could resolve. Only live methods are taken into account. The methods are
* sorted such that overriding methods appear before overriden methods.
*/
public Set resolvesTo(MethodRef method) {
TreeSet resolvesTo = (TreeSet) this.resolvesTo.get(method);
if (resolvesTo == null) {
resolvesTo = new TreeSet(new MemberRefComparator(context));
this.resolvesTo.put(method, resolvesTo);
Set liveMethods = this.liveMethods();
Iterator rtws = hier.resolvesToWith(method).iterator();
while (rtws.hasNext()) {
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws
.next();
if (liveMethods.contains(rtw.method)) {
resolvesTo.add(rtw.method);
}
}
}
// Return a clone so that the set may safely be modified
return ((Set) resolvesTo.clone());
}
/**
* Returns the methods (<tt>MemberRef</tt>s) to which a given method
* could resolve given that the receiver is in a certain set of types. Only
* live methods are taken into account. The methods are sorted such that
* overriding methods appear before overriden methods.
*/
public Set resolvesTo(MethodRef method, Set rTypes) {
if (rTypes.isEmpty()) {
return (resolvesTo(method));
}
// Since we're only dealing with a subset of types, don't bother
// with the caching stuff.
TreeSet resolvesTo = new TreeSet(new MemberRefComparator(context));
Set liveMethods = this.liveMethods();
Iterator rtws = hier.resolvesToWith(method).iterator();
while (rtws.hasNext()) {
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws
.next();
if (liveMethods.contains(rtw.method)) {
HashSet clone = (HashSet) rtw.rTypes.clone();
clone.retainAll(rTypes);
if (!clone.isEmpty()) {
// Only keep method that have at least one possible
// receiver type in rTypes
resolvesTo.add(rtw.method);
}
}
}
// Return a clone so that the set may safely be modified
return ((Set) resolvesTo.clone());
}
/**
* Returns the set of methods (<tt>MemberRef</tt>s) that the
* construction algorithm has deemed to be live.
*/
public Set liveMethods() {
// Not all of the methods in the calls mapping are necessarily
// live. So, we have to maintain a separate set.
return (this.liveMethods);
}
/**
* Returns the root methods (<tt>MemberRef</tt>s) of the call graph.
*/
public Set roots() {
return (this.roots);
}
/**
* Returns the set of classes (<tt>Type</tt>s) that are instantiated in
* the program.
*/
public Set liveClasses() {
return (this.liveClasses);
}
/**
* Prints a textual prepresentation of the <tt>CallGraph</tt> to a
* <tt>PrintWriter</tt>.
*
* @param out
* To where we print
* @param printLeaves
* If <tt>true</tt>, leaf methods (methods that do not call
* any other methods) are printed
*/
public void print(PrintWriter out, boolean printLeaves) {
Iterator callers = calls.keySet().iterator();
while (callers.hasNext()) {
MethodRef caller = (MethodRef) callers.next();
Iterator callees = ((Set) calls.get(caller)).iterator();
if (!printLeaves && !callees.hasNext()) {
continue;
}
out.print(caller.declaringClass() + "." + caller.name()
+ caller.getSignature());
if (roots.contains(caller)) {
out.print(" (root)");
}
out.println("");
while (callees.hasNext()) {
MethodRef callee = (MethodRef) callees.next();
// Only print live methods
if (!calls.containsKey(callee)) {
continue;
}
out.println(" " + callee.declaringClass() + "."
+ callee.name() + callee.getSignature());
}
out.println("");
}
}
/**
* Prints a summary of the call graph. Including the classes that are live
* and which methods are blocked.
*/
public void printSummary(PrintWriter out) {
out.println("Instantiated classes:");
Iterator instantiated = this.liveClasses.iterator();
while (instantiated.hasNext()) {
Type type = (Type) instantiated.next();
out.println(" " + type.toString());
}
out.println("\nBlocked methods:");
if (blocked != null) {
Iterator types = blocked.keySet().iterator();
while (types.hasNext()) {
Type type = (Type) types.next();
out.println(" " + type);
Set set = (Set) blocked.get(type);
if (set != null) {
Iterator methods = set.iterator();
while (methods.hasNext()) {
MethodRef method = (MethodRef) methods.next();
out.println(" " + method);
}
}
}
}
out.println("\nCall graph:");
this.print(out, false);
}
}
/**
* <tt>CallVisitor</tt> examines the instructions in a method and notices what
* methods are called and which classes are created.
*/
class CallVisitor extends InstructionAdapter {
MethodGen caller;
CallGraph cg;
boolean firstSpecial; // Are we dealing with the first invokespecial?
private static void db(String s) {
CallGraph.db(s);
}
public CallVisitor(CallGraph cg) {
this.cg = cg;
}
public void setCaller(MethodGen caller) {
this.caller = caller;
if (caller.getName().equals("<init>")) {
this.firstSpecial = true;
} else {
this.firstSpecial = false;
}
}
public void visit(Instruction inst, ConstantPoolGen cpg) {
if (inst instanceof InvokeInstruction) {
if (inst instanceof INVOKEVIRTUAL) {
visit_invokevirtual((InvokeInstruction) inst);
} else if (inst instanceof INVOKEINTERFACE) {
visit_invokeinterface((InvokeInstruction) inst);
} else if (inst instanceof INVOKESTATIC) {
visit_invokestatic((InvokeInstruction) inst);
} else if (inst instanceof INVOKESPECIAL) {
visit_invokespecial((InvokeInstruction) inst);
}
} else if (inst instanceof GETSTATIC) {
visit_getstatic((GETSTATIC) inst);
} else if (inst instanceof PUTSTATIC) {
visit_putstatic((PUTSTATIC) inst);
} else if (inst instanceof NEW) {
visit_new((NEW) inst);
}
}
public void visit_invokevirtual(InvokeInstruction inst, ConstantPoolGen cpg) {
db("\n Visiting Call: " + inst);
this.firstSpecial = false;
// Call doVirtual to determine which methods this call may resolve
// to are live.
MethodRef callee = new MethodRef((ObjectType) inst
.getReferenceType(cpg), new NameAndType(
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst
.getReturnType(cpg), inst.getArgumentTypes(cpg));
cg.doVirtual(caller, callee);
}
public void visit_invokeinterface(InvokeInstruction inst,
ConstantPoolGen cpg) {
db("\n Visiting Call: " + inst);
this.firstSpecial = false;
// Pretty much the same as invokevirtual
MethodRef callee = new MethodRef((ObjectType) inst
.getReferenceType(cpg), new NameAndType(
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst
.getReturnType(cpg), inst.getArgumentTypes(cpg));
cg.doVirtual(caller, callee);
}
public void visit_invokestatic(InvokeInstruction inst, ConstantPoolGen cpg) {
db("\n Visiting call: " + inst);
this.firstSpecial = false;
// There's not a lot to do with static methods since there is no
// dynamic dispatch.
MethodRef callee = new MethodRef((ObjectType) inst
.getReferenceType(cpg), new NameAndType(
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst
.getReturnType(cpg), inst.getArgumentTypes(cpg));
cg.addCall(caller, callee);
cg.worklist.add(callee);
}
public void visit_invokespecial(InvokeInstruction inst, ConstantPoolGen cpg) {
db("\n Visiting call: " + inst);
// Recall that invokespecial is used to call constructors, private
// methods, and "super" methods. There is no dynamic dispatch for
// special methods.
MethodRef callee = new MethodRef((ObjectType) inst
.getReferenceType(cpg), new NameAndType(
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst
.getReturnType(cpg), inst.getArgumentTypes(cpg));
MethodGen calleeMethod = null;
try {
calleeMethod = cg.context.editMethod(callee);
} catch (NoSuchMethodException ex1) {
System.err.println("** Couldn't find method: " + callee);
System.exit(1);
}
if (calleeMethod.isSynchronized() || calleeMethod.isNative()) {
// Calls to synchronized and native methods are virtual
cg.doVirtual(caller, callee);
} else {
// Calls to everything else (superclass methods, private
// methods, etc.) do not involve a dynamic dispatch and can be
// treated like a static method.
cg.addCall(caller, callee);
cg.worklist.add(callee);
}
cg.context.release(calleeMethod.getMethod(), calleeMethod
.getClassName());
}
public void visit_getstatic(GETSTATIC inst, ConstantPoolGen cpg) {
// Referencing a static fields implies that its class's static
// initializer has been invoked.
db("\n Referencing static field " + inst);
cg.addClinit((ObjectType) inst.getReferenceType(cpg));
}
public void visit_putstatic(PUTSTATIC inst, ConstantPoolGen cpg) {
// Referencing a static field implies that its class's static
// initializer has been invoked.
db("\n Referencing static field " + inst);
cg.addClinit((ObjectType) inst.getReferenceType(cpg));
}
public void visit_new(NEW inst, ConstantPoolGen cpg) {
// The new instruction instantiates a type and thus makes it live.
cg.makeLive(inst.getLoadClassType(cpg));
}
}
/**
* Compares <tt>MemberRef</tt>s such that overriding methods are less than
* overridden methods.
*/
class MemberRefComparator implements Comparator {
// TypeComparator c;
public MemberRefComparator(InlineContext context) {
// c = new TypeComparator(context);
}
public int compare(Object o1, Object o2) {
Assert.isTrue(o1 instanceof MethodRef, o1 + " is not a MethodRef");
Assert.isTrue(o2 instanceof MethodRef, o2 + " is not a MethodRef");
MethodRef ref1 = (MethodRef) o1;
MethodRef ref2 = (MethodRef) o2;
Type type1 = ref1.declaringClass();
Type type2 = ref2.declaringClass();
if (type1 instanceof ArrayType && type2 instanceof ArrayType) {
type1 = ((ArrayType) type1).getElementType();// TODO
type2 = ((ArrayType) type2).getElementType();
}
try {
if (type1 instanceof BasicType) {
if (type2 instanceof BasicType) {
return (type1 == type2 ? 1 : -1);
} else {
return -1;
}
}
if (type2 instanceof BasicType) {
return -1;
}
// Both must be ObjectTypes now
if (((ObjectType) type1).subclassOf((ObjectType) type2))
return -1;
} catch (ClassNotFoundException e) {
// Ignore, for now.
}
return 1;
}
public boolean compareTo(Object other) {
return (other instanceof MemberRefComparator);
}
}

@ -0,0 +1,730 @@
/*
* Class: Inline
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.inline;
import java.util.*;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.editor.MethodRef;
import edu.purdue.cs.bloat.editor.NameAndType;
import edu.purdue.cs.bloat.util.Assert;
/**
* Inlines the code of non-virtual method call sites. These sites include calls
* to static methods and certain uses of the <tt>invokespecial</tt> method.
* There are certain metrics that can be set to effect where and how inlining is
* performed.
*/
public class Inline {
public static boolean DEBUG = false;
private int maxCodeSize; // Max number of instructions in method
private int maxInlineSize; // Don't inline methods larger than this
private int maxCallDepth; // Max of height of call stack
private boolean inlineExceptions; // Inline methods that throw exceptions
private InlineContext context;
/**
* Size of the largest method that can be inlined
*/
public static int CALLEE_SIZE = 100000;
private static void db(String s) {
if (DEBUG) {
System.out.println(s);
}
}
/**
* Constructor. By default the first-level calls are only inlined one level
* deep, there is no max size on methods to inline, and methods that may
* throw exceptions are inlined.
*
* @param maxCodeSize
* The maximum number of instructions a method can grow to.
*/
public Inline(InlineContext context, int maxCodeSize) {
this.context = context;
this.maxCodeSize = maxCodeSize;
this.maxInlineSize = -1;
this.maxCallDepth = 1;
this.inlineExceptions = true;
}
/**
* Sets the maximum of size of a method that will be inlined. No method
* larger than this will be inlined.
*/
public void setMaxInlineSize(int maxInlineSize) {
this.maxInlineSize = maxInlineSize;
}
/**
* Sets the maximum number of nested calls we inline.
*/
public void setMaxCallDepth(int maxCallDepth) {
this.maxCallDepth = maxCallDepth;
}
/**
* Sets whether or not methods that may throw exceptions (that is, have a
* non-empty "throws" declaration) are inlined.
*/
public void setInlineExceptions(boolean inlineExceptions) {
this.inlineExceptions = inlineExceptions;
}
/**
* Scans a method and inlines non-virtual method calls according to this
* <tt>Inline</tt>'s metrics.
*/
public void inline(MethodGen method) {
ConstantPoolGen cpg = method.getConstantPool();
// Go through the method and look for calls to inline
StackHeightCounter stackHeight = new StackHeightCounter(method);
InstructionList code = method.getInstructionList();
FlowGraph.buildBLOATInstructionList(method);
boolean firstCall = true;
Iterator iter = code.iterator();
while (iter.hasNext()) {
InstructionHandle ih = (InstructionHandle) iter.next();
if (FlowGraph.label(ih)) {
// stackHeight.handle(ih);
// All instructions get handled later
db(" " + ih + "." + stackHeight.height() + ") " + ih
+ (FlowGraph.label(ih) ? " (starts block)" : ""));
}
Instruction inst = ih.getInstruction();
if (inst instanceof INVOKESTATIC || inst instanceof INVOKESPECIAL) {
InvokeInstruction iI = (InvokeInstruction) inst;
MethodRef callee = new MethodRef((ObjectType) iI
.getReferenceType(cpg), new NameAndType(iI
.getMethodName(cpg), iI.getReturnType(cpg)), iI
.getReturnType(cpg), iI.getArgumentTypes(cpg));
Stack callStack = new Stack();
callStack.add(new MethodRef(new ObjectType(method
.getClassName()), new NameAndType(method.getName(),
method.getReturnType()), method.getReturnType(), method
.getArgumentTypes()));
db(" Call: " + inst);
stackHeight.handle(ih);
int expectedHeight = stackHeight.height();
stackHeight.unhandle(ih);
InstructionHandle jh = ih;
ih = inline(method, callee, ih, callStack, stackHeight,
firstCall);
if (jh == ih) {
// Call was not inlined, add it to the stack
stackHeight.handle(ih);
db(" " + ih + "." + stackHeight.height() + ") " + inst);
}
int newHeight = stackHeight.height();
// If an exception is thrown as the last thing in a method
// newHeight will equal 0. Let's let this one slide.
Assert.isTrue(newHeight == 0 || newHeight == expectedHeight,
"Inlining did not get the stack heights right: "
+ "Expected " + expectedHeight + ", got "
+ newHeight);
} else {
stackHeight.handle(ih);
db(" " + ih + "." + stackHeight.height() + ") " + inst);
}
if (inst instanceof InvokeInstruction) {
firstCall = false;
}
}
// method.setCode(code); WE JUST MODIFIED IT SO CHANGES ARE COMMITED
if (DEBUG) {
stackHeight = new StackHeightCounter(method);
db("\nNew Code for " + method.getClassName() + "."
+ method.getName() + method.getReturnType());
code = method.getInstructionList();
Iterator iterator = method.getInstructionList().iterator();
InstructionHandle j = null;
while (iterator.hasNext()) {
j = (InstructionHandle) iterator.next();
if (FlowGraph.label(j)) {
// stackHeight.handle(j);
CodeExceptionGen[] tryCatches = method
.getExceptionHandlers();
for (int i = 0; i < tryCatches.length; i++) {
CodeExceptionGen tryCatch = tryCatches[i];
if (tryCatch.getStartPC().equals(j)) {
System.out.println(" Begin protected region");
}
if (tryCatch.getEndPC().equals(j)) {
System.out.println(" End protected region");
}
// A Label can both end a protected region and begin
// catch
// block
if (tryCatch.getHandlerPC().equals(j)) {
System.out.println(" Catch "
+ tryCatch.getCatchType());
}
}
}
stackHeight.handle(j);
System.out.println(" " + j + "." + stackHeight.height() + ") "
+ j.getInstruction()
+ (FlowGraph.label(j) ? " (starts block)" : ""));
}
// Print try-catch information
CodeExceptionGen[] tryCatches = method.getExceptionHandlers();
System.out.println("Exception information:");
for (int i = 0; i < tryCatches.length; i++) {
System.out.println(" " + tryCatches[i]);
}
System.out.println("");
}
}
/**
* Helper method that does most of the work. By calling this method
* recursively, we can inline more than one call deep.
*
* @param caller
* The original caller that got all of this started. Into this
* method we insert the code.
* @param callee
* The method to be inlined
* @param index
* Where in caller we insert inlined code
* @param callStack
* A stack of <tt>MemberRef</tt>s that represent the inlined
* methods that call other methods. It is used to detect
* recursion.
*
* @return The index into the caller's code array of the instruction
* following the last inlinined instruction. Start looking here
* after inline returns.
*/
// isRecursiveCount added so I can be sure of getting a unique local
// variable name
private InstructionHandle inline(MethodGen caller, MethodRef callee,
InstructionHandle index, Stack callStack,
StackHeightCounter stackHeight, boolean firstCall) {
Instruction newInst = null;
int LOCALVARINDEX = caller.getMaxLocals() - 1;
// Do we ignore the method being inlined?
if (context.ignoreMethod(callee)) {
db(" Can't inline " + callee + ": it's ignored");
index = index.getNext();
return (index);
}
// Can we inline this method
if (callStack.size() > maxCallDepth) {
db(" Can't inline " + callee + ": max call depth (" + maxCallDepth
+ ") reached");
index = index.getNext();
return (index);
} else if (callStack.contains(callee)) {
db(" Can't inline recursive call to " + callee);
index = index.getNext();
return (index);
}
// Make sure we're not inlining the static-ized version of a
// method in the call stack.
String name = callee.name();
// Is this stuff that BCEL would do? or has a BLOAT optimization done it
int b = name.indexOf("$$BLOAT");
if (b != -1) {
name = name.substring(0, b);
// Get rid of first parameter
Type[] oldParams = callee.paramTypes();
Type[] newParams = new Type[oldParams.length - 1];
for (int p = 1; p < oldParams.length; p++) {
newParams[p - 1] = oldParams[p];
}
MethodRef unBloated = new MethodRef(callee.declaringClass(),
new NameAndType(name, callee.returnType()), callee
.returnType(), newParams);
if (callStack.contains(unBloated)) {
db(" Can't inline recursive call to " + callee);
index = index.getNext();
return (index);
}
}
InstructionList code = caller.getInstructionList();
if (code.size() > maxCodeSize) {
db(" Can't inline " + callee + ": max code size (" + maxCodeSize
+ ") reached");
index = index.getNext();
return (index);
}
MethodGen calleeMethod = null;
try {
calleeMethod = context.editMethod(callee);
} catch (NoSuchMethodException ex) {
System.err.println("Couldn't find method " + callee);
ex.printStackTrace(System.err);
System.exit(1);
}
if (calleeMethod.isNative()) {
db(" Can't inline " + callee + ": it's a native method");
index = index.getNext();
return (index);
}
if (calleeMethod.isSynchronized()) {
db(" Can't inline " + callee + ": it's synchronized");
index = index.getNext();
return (index);
}
if (!inlineExceptions && calleeMethod.getExceptions().length > 0) {
db(" Can't inline " + callee + ": it may throw an exception");
index = index.getNext();
return (index);
}
if (calleeMethod.getInstructionList().size() > maxInlineSize) {
db(" Can't inline " + callee + ": it's too big");
index = index.getNext();
return (index);
}
// Methods that catch exceptions are problematic. When an
// exception is thrown, it clears the stack. Ordinarily this
// isn't a problem. However, now the stack of the caller is
// cleared in addition to the stack of the callee. This is bad.
// The callee might catch the exception and deal with it.
// However, the stack has still been cleared. This really messes
// things up for the code that appears after the inlined method.
// So, if a method catches an exception, we can only inline it if
// the stack contains nothing but the parameters to the call.
if (calleeMethod.getExceptionHandlers().length > 0) {
int size = 0;
Type[] args = callee.paramTypes();
for (int i = 0; i < args.length; i++) {
size = size + args[i].getSize();
}
if (stackHeight.height() > size) {
db(" Can't inline " + callee
+ ": It catches an exception and there's stuff on the "
+ "stack");
index = index.getNext();
return (index);
}
}
// If the callee method catches any of the same exceptions as the
// protected region that we are currently in, then we can't inline
// the method.
CodeExceptionGen[] tryCatches0 = calleeMethod.getExceptionHandlers();
for (int i = 0; i < tryCatches0.length; i++) {
CodeExceptionGen tc1 = tryCatches0[i];
Iterator iter = stackHeight.tryCatches().iterator();
while (iter.hasNext()) {
CodeExceptionGen tc2 = (CodeExceptionGen) iter.next();
Type t1 = tc1.getCatchType();
Type t2 = tc2.getCatchType();
if (t1 != null && t2 != null && t1.equals(t2)) {
db(" Can't inline " + callee
+ ": It catches the same type "
+ tc1.getCatchType().getClassName()
+ " as the current protected region");
index = index.getNext();
return (index);
}
}
}
// If the caller is a constructor and this is the first
// invokespecial we've seen in this callee method, we can inline
// calls to the constructors of superclasses and other
// constructors in this method. So, if this IS the first call in
// a method which IS a constructor, we can inline it.
if (calleeMethod.getName().equals("<init>")
&& (!firstCall || !caller.getName().equals("<init>"))) {
db(" Can't inline " + callee + ": It calls a normal constructor");
index = index.getNext();
return (index);
}
// Local variables are problematic. We cannot simply map the
// callee's variables to new variables in the caller because we
// cannot precisely determine the width of the variable the first
// time we see it. (For instance, Nate's generated code might use
// a local variable as a non-wide initially and then use it as a
// wide later.)
// Okay, we going to inline. Remove the calling instruction.
Instruction call = index.getInstruction();
try {
code.delete(index);
} catch (TargetLostException tle) {
// TargetLost? Oh well, go on with inlining
}
index = index.getPrev();
db(" Removing call: " + call);
Assert.isTrue(call instanceof INVOKESTATIC
|| call instanceof INVOKESPECIAL,
"Removing the wrong call instruction:" + call);
callStack.push(callee);
db(" Inlining call (" + callStack.size() + ") to "
+ callee.declaringClass() + "." + callee.name() + callee.type());
context.getInlineStats().noteInlined();
// ALL RIGHT, CREATE LOCALVARAIBLES FOR EACH OF THE LOCALS IN THE CALLEE
// The index should be LOCALVARINDEX + the index set in the calle code
// These will be added where they are params or garden variety locals.
// indexes shouldn't be a problem.
LocalVariableGen[] locals = calleeMethod.getLocalVariables();
for (int i = 0; i < locals.length; i++) {
caller.addLocalVariable("inline" + calleeMethod.getName() + i,
locals[i].getType(), index, index.getNext());
}
// First we have to pop the arguments off the stack and store them
// into the local variables. Remember that wide types occupy two
// local variables.
// Mapper mapper = new Mapper(caller);
// Type[] paramTypes = callee.paramTypes();
// IS THERE ANY REASON TO GO BACKWARDS?
for (int i = locals.length - 1; i >= 0; i--) {
// Map the local variables containing the arguments to new
// local variables.
Type paramType = locals[i].getType();
if (paramType == null) {
continue;
}
db(" Param " + i + ": of type " + paramType);
// LocalVariable newVar = mapper.map(param, paramType);
// I've already created the new LocalVariable
if (paramType instanceof ReferenceType) {
newInst = new ASTORE(locals[i].getIndex());
} else {
if (paramType.equals(Type.BOOLEAN)
|| paramType.equals(Type.BYTE)
|| paramType.equals(Type.CHAR)
|| paramType.equals(Type.SHORT)
|| paramType.equals(Type.INT)) {
newInst = new ISTORE(locals[i].getIndex());
} else if (paramType.equals(Type.DOUBLE)) {
newInst = new DSTORE(locals[i].getIndex());
} else if (paramType.equals(Type.LONG)) {
newInst = new LSTORE(locals[i].getIndex());
} else if (paramType.equals(Type.FLOAT)) {
newInst = new FSTORE(locals[i].getIndex());
} else {
throw new IllegalArgumentException("What's a " + paramType
+ "doing as a method " + "parameter");
}
}
index = caller.getInstructionList().append(index, newInst);
stackHeight.handle(index);
db(" " + index + "." + stackHeight.height() + "> " + newInst);
}
// SO ALL THE LOCALS ARE SETUP
// Before we mess with the code, we have to patch up the try-catch
// information from the inlined method to the caller method.
CodeExceptionGen[] tryCatches = calleeMethod.getExceptionHandlers();
for (int i = 0; i < tryCatches.length; i++) {
CodeExceptionGen tryCatch = tryCatches[i];
// INSTRUCTIONHANDLES STAY INTACT WHEN A INSTRUCTIONLIST IS
// ADDED
// SO WE DON"T NEED TO TRANSLATE LABELS AS BLOAT DID
InstructionHandle start = tryCatch.getStartPC();
InstructionHandle end = tryCatch.getEndPC();
InstructionHandle handler = tryCatch.getHandlerPC();
caller.addExceptionHandler(start, end, handler, tryCatch
.getCatchType());
}
// Go through the code in the callee method and inline it. Handle
// any calls by making a recursive call to this method. Copy each
// instruction to the method in which it is being inlined. Along
// the way convert references to local variables to their mapped
// values. Also remove return instructions. Replace them with
// loads as necessary.
FlowGraph.buildBLOATInstructionList(calleeMethod);
InstructionList inlineCode = calleeMethod.getInstructionList().copy();
// I want to play with the instructionlist and then add it to the caller
// code in one go which saves me messing with mapping instructionHandles
// We don't want to introduce a new end label because it confuses
// BLOAT during CFG construction. We designate the end label as
// starting a new block in hopes that it will solve problems with
// CFG construction.
InstructionHandle last = inlineCode.append(new NOP());
InstructionHandle endLabel;
if (FlowGraph.label(last)) {
endLabel = last;
} else {
FlowGraph.setLabel(last);
endLabel = last;
}
// endLabel.setStartsBlock(true);
firstCall = true;
Iterator iter = inlineCode.iterator();
while (iter.hasNext()) {
InstructionHandle instHandle = (InstructionHandle) iter.next();
Instruction inst = instHandle.getInstruction();
if (FlowGraph.label(instHandle)) {
// code.add(++index, newLabel);
// stackHeight.handle(newLabel);
db(" "
+ index
+ "."
+ stackHeight.height()
+ "> "
+ inst
+ (FlowGraph.label(instHandle) ? " (starts block)" : ""));
}
// Assert.isTrue(o instanceof Instruction, "What is a " + o +
// " doing in the instruction stream?");
// int opcode = inst.opcodeClass();
if (inst instanceof LocalVariableInstruction) {
// Map local variable in the callee method to local
// variables in the caller method.
// LocalVariable local = mapper.map((LocalVariable) operand,
// (inst.category() == 2 ? true : false));
// operand = local;
LocalVariableInstruction lvi = (LocalVariableInstruction) inst;
lvi.setIndex(lvi.getIndex() + LOCALVARINDEX);
// } else if(inst instanceof Label) {
// Map labels in the callee method to labels in the caller
// method.
// Label label = mapper.map((Label) operand);
// operand = label;
// HOPEFULLY THE InstructionHandles STAY INTACT
} else if (inst instanceof Select) {
// We have to patch up the Labels involved with the Switch
// Switch oldSwitch = (Switch) operand;
// Label newDefault = mapper.map(oldSwitch.defaultTarget());
// Label[] oldTargets = oldSwitch.targets();
// Label[] newTargets = new Label[oldTargets.length];
// for(int i = 0; i < newTargets.length; i++) {
// Label newTarget = mapper.map(oldTargets[i]);
// newTargets[i] = newTarget;
// }
// operand = new Switch(newDefault, newTargets,
// oldSwitch.values());
// HOPEFULLY THE InstructionHandles STAY INTACT
}
if (inst instanceof ReturnInstruction) {
// Insert a jump to the end of the inlined method. Any
// return value will be on top of the stack. This is where
// we want it.
newInst = new GOTO(endLabel);
instHandle.setInstruction(newInst);
// code.append(index, newInst);
index = index.getNext();
stackHeight.handle(instHandle);
db(" " + index + "." + stackHeight.height() + "> " + newInst);
} else if (inst instanceof INVOKESTATIC
|| inst instanceof INVOKESPECIAL) {
// Make a recursive call. Note that this must be done after
// we add the call instruction above. But we only want to
// visit the instruction with the stackHeight if the call was
// not inlined.
// newInst = new Instruction(opcode, operand);
// code.add(++index, newInst);
InvokeInstruction iI = (InvokeInstruction) inst;
stackHeight.handle(instHandle);
int expectedHeight = stackHeight.height();
stackHeight.unhandle(instHandle);
ConstantPoolGen cpg = calleeMethod.getConstantPool();
MethodRef nestedCall = new MethodRef((ObjectType) iI
.getReferenceType(cpg), new NameAndType(iI
.getMethodName(cpg), iI.getReturnType(cpg)), iI
.getReturnType(cpg), iI.getArgumentTypes(cpg));
InstructionHandle oldIndex = instHandle;
instHandle = inline(caller, nestedCall, instHandle, callStack,
stackHeight, firstCall);
if (instHandle == oldIndex) {
stackHeight.handle(instHandle);
db(" " + instHandle + "." + stackHeight.height() + "> "
+ inst);
}
int newHeight = stackHeight.height();
Assert.isTrue(newHeight == 0 || newHeight == expectedHeight,
"Inlining did not get the stack heights right: "
+ "Expected " + expectedHeight + ", got "
+ newHeight);
} else {
// Add the instruction
// newInst = new Instruction(opcode, operand);
// code.add(++index, newInst);
stackHeight.handle(instHandle);
db(" " + index + "." + stackHeight.height() + "> " + newInst);
}
// We want to do this after we've made any recursive calls to
// inline.
if (inst instanceof InvokeInstruction) {
firstCall = false;
}
}
code.append(index, inlineCode);
index = endLabel.getNext();
// add the whole of the inline method code now that it has been modified
// if(addEndLabel) {
// Done inlining. Add end label.
// code.add(++index, endLabel);
// stackHeight.handle(endLabel);
// db(" " + index + "." + stackHeight.height() + "> " + endLabel +
// (endLabel.startsBlock() ? " (starts block)" : ""));
// }
// caller.setDirty(true);
callStack.pop();
return (index);
}
}
/**
* Utility class for mapping local variables and labels. Note that when mapping
* local variables we have to be careful. We can't assume that a variable will
* retain its "wideness" throughout the method. I learned this one the hard way.
* So, we have to keep a constant difference between the mapped variables.
*/
/*
* class Mapper { private Map varsMap; // Maps local variables //private Map
* labelsMap; // Maps labels private MethodGen method; // Method into which
* things are mapped //private int offset; // Start numbering new locals here
* //adding locals to method will do this for us.
*
* private static void db(String s) { if(Inline.DEBUG) System.out.println(s); }
*/
/**
* Constructor.
*/
/*
* public Mapper(MethodGen method) { this.method = method; varsMap = new
* HashMap(); labelsMap = new LinkedHashMap(); offset = method.maxLocals() + 1; }
*
* public Label map(Label label) { Label newLabel = (Label)
* labelsMap.get(label); if(newLabel == null) { newLabel =
* this.method.newLabel(); newLabel.setStartsBlock(label.startsBlock());
* labelsMap.put(label, newLabel); db(" " + label + " -> " + newLabel +
* (newLabel.startsBlock() ? " (starts block)" : "")); } return(newLabel); }
*
* public LocalVariableGen map(LocalVariableGen var, Type type) {
* LocalVariableGen newVar = (LocalVariableGen) varsMap.get(var); if(newVar ==
* null) { newVar = this.method.localAt(var.index() + offset); // newVar =
* this.method.newLocal(type); varsMap.put(var, newVar); db(" " + var + " (" +
* var.index() + ") -> " + newVar + "(" + var.index() + "+" + offset + ")" +
* (type.isWide() ? " (" + type + ")" : "")); } return(newVar); }
*
* public LocalVariable map(LocalVariable var, boolean isWide) { LocalVariable
* newVar = (LocalVariable) varsMap.get(var); if(newVar == null) { newVar =
* this.method.localAt(var.index() + offset); // newVar =
* this.method.newLocal(isWide); varsMap.put(var, newVar); db(" " + var + " (" +
* var.index() + ") -> " + newVar + "(" + var.index() + "+" + offset + ")" +
* (isWide ? " (wide)" : "")); } return(newVar); } }
*/

@ -0,0 +1,122 @@
/*
* Class: InlineContext
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.inline;
import java.util.*;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.editor.EditorContext;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.editor.MethodRef;
/**
* An <Tt>InlineContext</tt> gives access to the <Tt>CallGraph</tt> for the
* program whose classes are being operated on by BLOAT.
*/
public interface InlineContext extends EditorContext {
/**
* Returns the call graph for the program.
*/
public CallGraph getCallGraph();
/**
* Sets the root methods for this <tt>InlineContext</tt>.
*
* @param roots
* The root methods (<tt>MemberRef</tt>s) of the program
* @throws IllegalStateException
* Call graph has already been created with different roots.
*/
public void setRootMethods(Set roots);
/**
* Returns an <tt>InlineStats</tt> object for getting statistics about
* inlining.
*/
public InlineStats getInlineStats();
/**
* Notes that all classes, methods, and fields in a package should be
* "ignored" by inlining. That is, methods won't be inlined, classes won't
* be involved in specialization, etc. Note that it is exceptable to just
* add a prefix of a package name. For instance, adding "java" will ignore
* java.lang.Object, java.io.File, etc.
*/
public void addIgnorePackage(String name);
/**
* Notes that a class should be ignored by inlining. That is, none of its
* methods will be inlined and it won't be involved in specialization.
*/
public void addIgnoreClass(Type type);
/**
* Notes that a method should be ignored by inlining. That is, it will not
* be inlined.
*/
public void addIgnoreMethod(MethodRef method);
/**
* Notes that a field should be ignored by inlining.
*/
public void addIgnoreField(MemberRef field);
/**
* Returns <tt>true</tt> if a class should be ignored by inlining.
*/
public boolean ignoreClass(Type type);
/**
* Returns <tt>true</tt> if a method should be ignored by inlining.
*/
public boolean ignoreMethod(MethodRef method);
/**
* Returns <tt>true</tt> if a field should be ignored by inlining.
*/
public boolean ignoreField(MemberRef field);
/**
* Sets whether or not we ignore all system classes.
*/
public void setIgnoreSystem(boolean ignoreSystem);
}

@ -0,0 +1,152 @@
/*
* Class: InlineStats
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.inline;
import java.io.*;
import java.util.*;
/**
* This class is used to gather statistics about inlining. Examples of such
* statistics are the number of call sites virtual methods resolve to and the
* number of live classes and methods.
*/
public class InlineStats {
private String configName; // Name of configuration
private Map morphicity; // Maps morphic number to count
private int nLiveClasses; // Number of live classes
private int nLiveMethods; // Number of live methods
private int nNoPreexist; // Number of non-preexistent calls
private int nInlined; // Number of methods inlined
/**
* Constructor.
*
* @param configName
* A string describing the configuration being run
*/
public InlineStats() {
this.configName = "Inlining stats";
this.morphicity = new TreeMap();
this.nLiveClasses = 0;
this.nLiveMethods = 0;
this.nNoPreexist = 0;
this.nInlined = 0;
}
/**
* Sets the configuration name for this <tt>InlineStats</tt>.
*/
public void setConfigName(String configName) {
this.configName = configName;
}
/**
* Maintains a count of the number of methods call sites resolve to. May
* give an idea as to how "dynamic" a program is.
*/
public void noteMorphicity(int morphicity) {
Integer r = new Integer(morphicity);
Integer count = (Integer) this.morphicity.get(r);
if (count == null) {
this.morphicity.put(r, new Integer(1));
} else {
this.morphicity.put(r, new Integer(count.intValue() + 1));
}
}
/**
* Notes that a call site's receiver is not preexistent.
*/
public void noteNoPreexist() {
nNoPreexist++;
}
/**
* Notes that a method was inlined
*/
public void noteInlined() {
this.nInlined++;
}
/**
* Notes the number of live methods.
*/
public void noteLiveMethods(int nLiveMethods) {
this.nLiveMethods = nLiveMethods;
}
/**
* Notes the number of live classes.
*/
public void noteLiveClasses(int nLiveClasses) {
this.nLiveClasses = nLiveClasses;
}
/**
* Print a summary of the statistics to a <tt>PrintWriter</tt>.
*/
public void printSummary(PrintWriter pw) {
pw.println("Statistics for " + this.configName + " (" + new Date()
+ ")");
pw.println(" Number of live classes: " + this.nLiveClasses);
pw.println(" Number of live methods: " + this.nLiveMethods);
pw.println(" Call site morphism:");
Iterator morphs = this.morphicity.keySet().iterator();
int total = 0;
while (morphs.hasNext()) {
Integer morph = (Integer) morphs.next();
Integer count = (Integer) this.morphicity.get(morph);
total += count.intValue();
pw.println(" " + morph + "\t" + count);
}
pw.println(" Total number of call sites: " + total);
pw.println(" Number of non-preexistent call sites: " + nNoPreexist);
pw.println(" Number of inlined methods: " + nInlined);
}
}

@ -0,0 +1,30 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
CallGraph.class\
Inline.class\
InlineContext.class\
InlineStats.class\
InstructionStack.class\
StackHeightCounter.class
include ../class.mk

@ -0,0 +1,246 @@
/*
* Class: StackHeightCounter
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.inline;
import java.util.*;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.editor.InstructionAdapter;
/**
* Used to keep track of the height of the stack. As instructions are visited,
* the height of the stack is adjusted accordingly.
*/
public class StackHeightCounter extends InstructionAdapter {
public static boolean DEBUG = false;
private int height; // Current stack height
private LinkedHashMap labelHeights; // Maps labels to their heights as
// Integers
private MethodGen method; // Method whose height we're computing
Set tryCatches; // TryCatches active at current instruction
private static void db(String s) {
if (DEBUG)
System.out.println(s);
}
/**
* Constructor.
*
* @param height
* Initial height of stack
*/
public StackHeightCounter(MethodGen method) {
this.method = method;
this.height = 0;
this.labelHeights = new LinkedHashMap();
this.tryCatches = new LinkedHashSet();
}
/**
* Returns the current height of the stack.
*/
public int height() {
return (this.height);
}
/**
* Handles a Label. Special provisions must be made for labels that catch
* exceptions.
*/
// public void handle(Label label) {
// }
// EVERYTHING IS A INSTRUCTION NOW
/**
* Handles an instruction. Special provisions must be made to handle jumps,
* switches, throws, and returns.
*/
public void handle(InstructionHandle ih) {
if (FlowGraph.label(ih)) {
Integer labelHeight = (Integer) labelHeights.get(ih);
if (labelHeight != null) {
height = labelHeight.intValue();
}
// If this label begins an exception handler, then start it off
// with a new stack with one element (the exception object) on
// it.
CodeExceptionGen[] tryCatches = method.getExceptionHandlers();
for (int i = 0; i < tryCatches.length; i++) {
if (tryCatches[i].getHandlerPC().equals(ih)) {
FlowGraph.setLabel(ih);
height = 1;
break;
}
if (tryCatches[i].getStartPC().equals(ih)) {
// If this block starts a protected region make note of
// the
// TryCatch block
this.tryCatches.add(tryCatches[i]);
}
if (tryCatches[i].getEndPC().equals(ih)) {
// If this block ends a protected region, remove it from
// the
// tryCatches list
this.tryCatches.remove(tryCatches[i]);
}
}
}// ends the bit where we handle Labels but because a labels are
// Instructions also....
Instruction inst = ih.getInstruction();
// inst.visit(this);
// Hopefully this avoids that annoying switch statement and all
// those visits
int delta = 0;
if (inst instanceof StackConsumer)
delta = delta
- ((StackConsumer) inst).consumeStack(method
.getConstantPool());
if ((inst instanceof StackProducer))// &&!(inst instanceof
// JsrInstruction))
delta = delta
- ((StackProducer) inst).produceStack(method
.getConstantPool());
this.height = this.height + delta;
if (inst instanceof IfInstruction || inst instanceof GotoInstruction) {
BranchInstruction bI = (BranchInstruction) inst;
InstructionHandle target = bI.getTarget();
FlowGraph.setLabel(target);
Integer targetHeight = (Integer) labelHeights.get(target);
if (targetHeight != null) {
if (targetHeight.intValue() != height) {
// Make sure stack heights match
db("Stack height mismatch (" + targetHeight.intValue()
+ " != " + height + ") at " + inst);
}
} else {
labelHeights.put(target, new Integer(height));
}
} else if (inst instanceof Select) {
// Propagate height to all targets
Select sw = (Select) inst;
InstructionHandle[] targets = sw.getTargets();
for (int t = 0; t < targets.length; t++) {
InstructionHandle target = targets[t];
FlowGraph.setLabel(target);
Integer targetHeight = (Integer) labelHeights.get(target);
if (targetHeight != null) {
if (targetHeight.intValue() != height) {
// Make sure stack heights match
db("Stack height mismatch (" + targetHeight.intValue()
+ " != " + height + ") at " + inst);
}
} else {
labelHeights.put(target, new Integer(height));
}
}
} else if (inst instanceof JsrInstruction) {
// We have to account for the return address being pushed on the
// stack. Let's ignore the fact that someday in the future
// subroutines may push stuff on the stack. M'kay?
InstructionHandle subroutine = ((JsrInstruction) inst).getTarget();
FlowGraph.setLabel(subroutine);
Integer subHeight = (Integer) labelHeights.get(subroutine);
if (subHeight != null) {
if (subHeight.intValue() != height + 1) {
db("Stack height mismatch at subroutine ("
+ subHeight.intValue() + " != " + (height + 1)
+ ") at " + inst);
}
} else {
labelHeights.put(subroutine, new Integer(height + 1));
}
} else if (inst instanceof ExceptionThrower
|| inst instanceof ReturnInstruction) {
// Clear the stack
height = 0;
}
}
/**
* Simulates the effect of "backing up" over an instruction.
*/
public void unhandle(InstructionHandle inst) {
// Temporarily negate the stack height, perform the normal handle,
// and then negate the stack height again.
this.height = -this.height;
this.handle(inst);
this.height = -this.height;
}
/**
* Returns the set of <tt>TryCatch</tt> objects for the protected region
* that the current instruction may be in.
*/
public Set tryCatches() {
return (this.tryCatches);
}
/*
* public void visit_lushr(Instruction inst) { // Yes, it's only -1. The
* long and the int index are popped off // and the shifted value is pushed.
* Net loss of 1. height -= 1; }
*
* public void visit_jsr(Instruction inst) { // Even though the jsr
* instruction itself pushes the return // address onto the stack, we don't
* want to account for that // here. It is already taken care of in the
* handle method. This // way the label following the jsr (the return site)
* will have the // stack height it had before the call. Once again, we do
* not // account for the possibility of the jsr modifying the height of //
* the stack. height += 0; }
*
*/
}

@ -0,0 +1,19 @@
<html>
<body>
<p>Classes for performing method inlining. The first step in method
ininling is to create the call graph for a Java "program". Rapid Type
Analysis [Bacon 1997] is used to keep the size of the call graph
managable. RTA uses the class hierarchy to determine all possible
methods that may be invoked at a given call site. Methods are only
considered to be live if their class is instantiated somewhere in the
program.</p>
<p>Call sites are specialized using the resolves-to information
supplied by the call graph. Each virtual method call is transformed
into a "switch" statement on the possible receiver types. The
receiver is cast to a given type and a static method is invoked in
place of the virtual method.</p>
</body>
</html>

@ -0,0 +1,126 @@
/*
* Class: CodeGen
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
import java.text.DateFormat;
import java.util.Date;
import edu.purdue.cs.bloat.codegen.RegisterAllocator;
import edu.purdue.cs.bloat.codegen.CodeGenerator;
/**
* CodeGen generates the code after the other optimizations have been performed.
* It's an Optimization itself, so you have to make sure it gets put in the list
* of optimizations to perform.
* <p>
*
* CodeGen will print debugging information if the system property
* <tt>edu.purdue.cs.bloat.DEBUG</tt> is set to <tt>true</tt>.
*
* @author Chris Bennetts
*
*/
public class CodeGen implements Optimization {
private RegisterAllocator alloc = null;
private static DateFormat dateFormat = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.LONG);
private final boolean DEBUG;
public CodeGen(RegisterAllocator alloc) {
DEBUG = "true".equals(System.getProperty("edu.purdue.cs.bloat.DEBUG"));
this.alloc = alloc;
}
public void transform(MethodState state) {
// Liveness and RegisterAllocation take place in CodeGenerator
CodeGenerator codegen = new CodeGenerator(state);
// Register allocation must occur before replacePhis().
printTraceMessage(" Register allocation");
codegen.replacePhis();
printPostPhisMessage(state);
codegen.simplifyControlFlow();
codegen.allocateReturnAddresses(alloc);
printPostAllocationMessage(state);
codegen.generateCode();
}
public String traceMessage(String dateString) {
return " Code Generation: " + dateString;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
private void printTraceMessage(String root) {
if (true)
return;
String dateString = dateFormat.format(new Date());
System.out.println(root + ": " + dateString);
}
private void printPostPhisMessage(MethodState state) {
if (DEBUG) {
System.out.println("After fixing Phis------------------------");
state.controlFlowGraph().print(System.out);
System.out.println("End print--------------------------------");
}
}
private void printPostAllocationMessage(MethodState state) {
if (DEBUG) {
System.out.println("After removing empty blocks--------------");
state.controlFlowGraph().print(System.out);
System.out.println("End print--------------------------------");
}
}
}

@ -0,0 +1,70 @@
/*
* Class: ConstantPoolSizePrinter
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
/**
* Prints the size of the constant pool. Neatly packaged into an Optimization so
* that it can be inserted at any point in the optimization cycle.
*
* @author Chris Bennetts
*
*/
public class ConstantPoolSizePrinter implements Optimization {
public void transform(MethodState state) {
int size = state.methodGen().getConstantPool().getSize();
System.out.println("ConstantPool size: " + size);
}
public String traceMessage(String dateString) {
return null;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
public static void print(MethodState state) {
(new ConstantPoolSizePrinter()).transform(state);
}
}

@ -0,0 +1,921 @@
/*
* Class: Main
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
import org.apache.bcel.util.ClassPath;
import org.apache.bcel.util.Repository;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import edu.purdue.cs.bloat.cfg.DominatorTree;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.cfg.VerifyCFG;
import edu.purdue.cs.bloat.codegen.CodeGenerator;
import edu.purdue.cs.bloat.codegen.Liveness;
import edu.purdue.cs.bloat.context.BloatContext;
import edu.purdue.cs.bloat.context.PersistentBloatContext;
import edu.purdue.cs.bloat.diva.InductionVarAnalyzer;
import edu.purdue.cs.bloat.editor.ClassHierarchy;
import edu.purdue.cs.bloat.inline.StackHeightCounter;
import edu.purdue.cs.bloat.ssa.SSA;
import edu.purdue.cs.bloat.ssa.SSAGraph;
import edu.purdue.cs.bloat.tbaa.TypeInference;
import edu.purdue.cs.bloat.trans.DeadCodeElimination;
import edu.purdue.cs.bloat.trans.ExprPropagation;
import edu.purdue.cs.bloat.trans.Peephole;
import edu.purdue.cs.bloat.trans.SSAPRE;
import edu.purdue.cs.bloat.trans.StackOpt;
import edu.purdue.cs.bloat.trans.StackOptimization;
import edu.purdue.cs.bloat.trans.ValueFolding;
import edu.purdue.cs.bloat.trans.ValueNumbering;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.codegen.RegisterAllocator;
import java.io.*;
import java.text.*;
import java.util.*;
/**
* Usage: java edu.purdue.cs.bloat.optimize.Main [-options] classes dir
*
* where options include: -help print out this message -v -verbose turn on
* verbose mode -debug display a hideous amount of debug info -classpath
* <directories separated by colons> list directories in which to look for
* classes -f optimize files even if up-to-date -closure recursively optimize
* referenced classes -relax-loading don't report errors if a class is not found
* -skip <class|package.*> skip the given class or package -only
* <class|package.*> skip all but the given class or package -preserve-debug try
* to preserve debug information -[no]anno insert an annotation in the contant
* pool -[no]stack-alloc try to push locals onto the operand stack -peel-loops
* <n|all> peel innermost loops to enable code hoisting (n >= 0 is the maximum
* loop level to peel) -[no]pre perform partial redundency elimination
* -[no]appre perform partial redundency elimination on access paths -[no]dce
* perform dead code elimination -diva perform demand-driven induction variable
* analysis -[no]prop perform copy and constant propagation
*
*/
public class Main {
// the default class path to read the classes from
static String DEFAULT_CLASSPATH = ".";
// Flags that can be set/unset from the command line
static boolean DEBUG = false; // Display debugging information
static boolean VERBOSE = false;// Display status information as program
// runs
public static boolean TRACE = false;// Track our progress
static boolean FORCE = false;// Optimize file even if they are
// up-to-date
static boolean CLOSURE = false;// Opimtize over entire heirarchy (i.e.
// start
// at the specified classes and recurse up the
// class heirarchy)
static DateFormat dateFormat = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.LONG);
static boolean DIVA = false;
public static boolean PRE = true;
public static boolean DCE = true;
public static boolean PROP = true;
public static boolean FOLD = true; // Value folding
public static boolean INFER = true; // Type inference
public static boolean NUMBER = true; // Value numbering
public static boolean PERSIST = false; // Persistent check elimination
public static boolean STACK_ALLOC = false;
static boolean ANNO = true; // Note that class file was optimized
public static boolean VERIFY = true;
public static boolean OPT_STACK_1 = false; // Perform stack optimizations
public static boolean OPT_STACK_2 = false;
static String[] ARGS = null; // Arguments from the command line
public static List SKIP = new ArrayList();
// Classes that are specifically not optimized
static List ONLY = new ArrayList();
// Classes that are specifically optimized
static String METHOD = null; // The name of one method to edit
static BloatContext context = null;
// static ClassFileLoader loader = null;//Used to load classes from
// class files
static Repository loader = null;
static File outputDir = null;
public static List optimizationsToPerform = null;
/**
* Parses the command line. The user must specify at least one class to
* optimize and the directory in which to place the optimized class files.
* The methods of the specified classes are then optimized according to the
* command line options.
*
* @see ClassEditor
* @see ClassFileLoader
* @see ClassFile
* @see MethodEditor
* @see MethodInfo
*
* @see CompactArrayInitializer
* @see FlowGraph
*
*/
public static void main(String[] args) {
try {
ClassPath classPath = new ClassPath(DEFAULT_CLASSPATH);
List classes = new ArrayList(args.length); // The classes to
// optimize
boolean gotdir = false; // Has an output directory been
// specified?
ARGS = args;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-v") || args[i].equals("-verbose")) {
VERBOSE = true;
} else if (args[i].equals("-debug")) {
DEBUG = true;
FlowGraph.DEBUG = true;
DominatorTree.DEBUG = true;
Tree.DEBUG = true;
CodeGenerator.DEBUG = true;
Liveness.DEBUG = true;
SSA.DEBUG = true;
SSAGraph.DEBUG = true;
// PersistentCheckElimination.DEBUG = true;
ValueNumbering.DEBUG = true;
ValueFolding.DEBUG = true;
ClassHierarchy.DEBUG = true;
TypeInference.DEBUG = true;
SSAPRE.DEBUG = true;
ExprPropagation.DEBUG = true;
DeadCodeElimination.DEBUG = true;
CodeGenerator.DB_OPT_STACK = true;
} else if (args[i].equals("-trace")) {
TRACE = true;
} else if (args[i].equals("-db")) {
if (++i >= args.length) {
System.err.println("** No debugging option specified");
usage();
}
if (args[i].equals("bc")) {
// CodeArray.DEBUG = true;
} else if (args[i].equals("cfg")) {
FlowGraph.DEBUG = true;
} else if (args[i].equals("ssa")) {
SSA.DEBUG = true;
SSAGraph.DEBUG = true;
} else if (args[i].equals("graphs")) {
FlowGraph.DB_GRAPHS = true;
} else if (args[i].startsWith("-")) {
i--;
} else {
System.err.println("** Unknown debugging option: "
+ args[i]);
usage();
}
} else if (args[i].equals("-debugvf")) {
ValueFolding.DUMP = true;
} else if (args[i].equals("-debugbc")) {
// BloatContext.DEBUG = true;
} else if (args[i].equals("-help")) {
usage();
} else if (args[i].equals("-noanno")) {
ANNO = false;
} else if (args[i].equals("-anno")) {
ANNO = true;
} else if (args[i].equals("-print-flow-graph")) {
FlowGraph.PRINT_GRAPH = true;
} else if (args[i].equals("-preserve-debug")) {
// CodeGenerator.PRESERVE_DEBUG = true;
} else if (args[i].equals("-nouse-stack-vars")) {
Tree.USE_STACK = false;
} else if (args[i].equals("-use-stack-vars")) {
Tree.USE_STACK = true;
} else if (args[i].equals("-unique-handlers")) {
// CodeGenerator.UNIQUE_HANDLERS = true;
} else if (args[i].equals("-nostack-alloc")) {
STACK_ALLOC = false;
} else if (args[i].equals("-stack-alloc")) {
STACK_ALLOC = true;
} else if (args[i].equals("-no-verify")) {
VERIFY = false;
} else if (args[i].equals("-peel-loops")) {
if (++i >= args.length) {
usage();
}
String n = args[i];
if (n.equals("all")) {
FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS;
} else {
try {
FlowGraph.PEEL_LOOPS_LEVEL = Integer.parseInt(n);
if (FlowGraph.PEEL_LOOPS_LEVEL < 0) {
usage();
}
} catch (NumberFormatException ex) {
usage();
}
}
} else if (args[i].equals("-color")) {
Liveness.UNIQUE = false;
} else if (args[i].equals("-nocolor")) {
Liveness.UNIQUE = true;
} else if (args[i].equals("-only-method")) {
if (++i >= args.length) {
usage();
}
METHOD = args[i];
} else if (args[i].equals("-classpath")) {
if (++i >= args.length) {
usage();
}
classPath = new ClassPath(args[i]);
} else if (args[i].equals("-classpath/p")) {
if (++i >= args.length) {
usage();
}
classPath = new ClassPath(args[i]);
} else if (args[i].equals("-skip")) {
if (++i >= args.length) {
usage();
}
String pkg = args[i];
// Account for class file name on command line
if (pkg.endsWith(".class"))
pkg = pkg.substring(0, pkg.lastIndexOf('.'));
SKIP.add(pkg.replace('.', '/'));
} else if (args[i].equals("-only")) {
if (++i >= args.length) {
usage();
}
String pkg = args[i];
// Account for class file name on command line
if (pkg.endsWith(".class"))
pkg = pkg.substring(0, pkg.lastIndexOf('.'));
ONLY.add(pkg.replace('.', '/'));
} else if (args[i].equals("-nodce")) {
DCE = false;
} else if (args[i].equals("-noprop")) {
PROP = false;
} else if (args[i].equals("-noappre")) {
SSAPRE.NO_ACCESS_PATHS = true;
} else if (args[i].equals("-nopre")) {
PRE = false;
} else if (args[i].equals("-dce")) {
DCE = true;
} else if (args[i].equals("-prop")) {
PROP = true;
} else if (args[i].equals("-appre")) {
SSAPRE.NO_ACCESS_PATHS = false;
} else if (args[i].equals("-pre")) {
PRE = true;
} else if (args[i].equals("-closure")) {
CLOSURE = true;
} else if (args[i].equals("-opt-stack-1")) {
OPT_STACK_1 = true;
CodeGenerator.OPT_STACK = true;
} else if (args[i].equals("-opt-stack-2")) {
OPT_STACK_2 = true;
CodeGenerator.OPT_STACK_2 = true;
} else if (args[i].equals("-diva")) {
DIVA = true;
} else if (args[i].equals("-no-thread")) {
SSAPRE.NO_THREAD = true;
} else if (args[i].equals("-no-precise")) {
SSAPRE.NO_PRECISE = true;
} else if (args[i].equals("-relax-loading")) {
ClassHierarchy.RELAX = true;
} else if (args[i].equals("-f") || args[i].equals("-force")) {
FORCE = true;
} else if (args[i].startsWith("-")) {
System.err.println("No such option: " + args[i]);
usage();
} else if (i == args.length - 1) {
// Last argument is the name of the output directory
File f = new File(args[i]);
if (f.exists() && !f.isDirectory()) {
System.err.println("No such directory: " + f.getPath());
System.exit(2);
}
if (!f.exists()) {
f.mkdirs();
}
if (!f.exists()) {
System.err.println("Couldn't create directory: "
+ f.getPath());
System.exit(2);
}
// Tell class loader to put optimized classes in f
// directory
outputDir = f;
gotdir = true;
} else {
// The argument must be a class name...
classes.add(args[i]);
}
}
loader = org.apache.bcel.util.SyntheticRepository
.getInstance(classPath);
if (!gotdir) {
System.err.println("No output directory specified");
usage();
}
if (classes.size() == 0) {
System.err.println("** No classes specified");
usage();
}
if (TRACE)
System.setProperty("edu.purdue.cs.bloat.TRACE", "true");
if (DEBUG)
System.setProperty("edu.purdue.cs.bloat.DEBUG", "true");
// Use the CachingBloatingContext
context = new PersistentBloatContext(loader, CLOSURE);
buildOptimizationsToPerform();
boolean errors = false;
Iterator iter = classes.iterator();
// Now that we've parsed the command line, load the classes into
// the
// class loader
while (iter.hasNext()) {
String name = (String) iter.next();
try {
context.loadClass(name);
} catch (ClassNotFoundException ex) {
System.err.println("Couldn't find class: "
+ ex.getMessage());
errors = true;
}
}
if (errors) {
System.exit(1);
}
if (!CLOSURE) {
Iterator e = classes.iterator();
// Edit only the classes that were specified on the command line
while (e.hasNext()) {
String name = (String) e.next();
editClass(name);
}
} else {
// Edit all the classes in the class file editor and their
// superclasses
classes = null;
if (TRACE) {
System.out.println("Computing closure "
+ dateFormat.format(new Date()));
}
Iterator e = context.getHierarchy().classes().iterator();
while (e.hasNext()) {
Type t = (Type) e.next();
if (t instanceof ObjectType) {
editClass(((ObjectType) t).getClassName());
}
}
}
} catch (ExceptionInInitializerError ex) {
ex.printStackTrace();
System.out.println(ex.getException());
}
}
private static void usage() {
System.err
.println("\nUsage: java edu.purdue.cs.bloat.optimize.Main"
+ "\n [-options] classes dir"
+ "\n"
+ "\nwhere options include:"
+ "\n -help print out this message"
+ "\n -v -verbose turn on verbose mode"
+ "\n -debug display a hideous amount of debug info"
+ "\n -classpath <directories separated by colons>"
+ "\n list directories in which to look for classes"
+ "\n -f optimize files even if up-to-date"
+ "\n -closure recursively optimize referenced classes"
+ "\n -relax-loading don't report errors if a class is not found"
+ "\n -skip <class|package.*>"
+ "\n skip the given class or package"
+ "\n -only <class|package.*>"
+ "\n skip all but the given class or package"
+ "\n -preserve-debug try to preserve debug information"
+ "\n -[no]anno insert an annotation in the contant pool"
+ "\n -[no]stack-alloc try to push locals onto the operand stack"
+ "\n -peel-loops <n|all>"
+ "\n peel innermost loops to enable code hoisting"
+ "\n (n >= 0 is the maximum loop level to peel)"
+ "\n -[no]pre perform partial redundency elimination"
+ "\n -[no]dce perform dead code elimination"
+ "\n -diva perform demand-driven induction variable analysis"
+ "\n -[no]prop perform copy and constant propagation"
+ "");
System.exit(0);
}
/**
* Performs the actual editing of a class. Does a whole mess of stuff
* including reading in the classfile, building data structures to represent
* the class file, converting the CFG for each method in the class into SSA
* form, perform some anlayses and optimizations on the method, and finally
* committing it back to the class file. Phew.
*/
private static void editClass(String className) {
JavaClass classFile; // Holds info about a class (implements
// ClassInfo)
File targetFile = null;
// Get information about the class className
try {
classFile = (JavaClass) context.loadClass(className);
} catch (ClassNotFoundException ex) {
System.err.println("** Couldn't find class: " + ex.getMessage());
return;
}
// Check to see if the file is up-to-date (i.e. has been
// recompiled since it was last optimized). If so, do nothing
// because the FORCE flag is false.
String source = classFile.getSourceFileName();
System.out.println(source + " source file for class:"
+ classFile.getClassName());
File sourceFile = new File(source);
String target = outputDir.getAbsolutePath()
+ File.separatorChar
+ classFile.getClassName().substring(
classFile.getClassName().lastIndexOf(".") + 1)
+ ".class";
System.out.println(target + " selected for output of class: "
+ classFile.getClassName());
targetFile = new File(target);
if (!FORCE) {
if (sourceFile != null && targetFile != null && sourceFile.exists()
&& targetFile.exists()
&& sourceFile.lastModified() < targetFile.lastModified()) {
if (VERBOSE) {
System.out.println(classFile.getClassName()
+ " is up to date");
}
return;
}
// return;
}
if (DEBUG) {
// Print the contents of the class file to System.out
System.out.println(classFile);
}
ClassGen c = context.editClass(classFile);
boolean skip = false;
String name = c.getClassName();
String qual = "";
if (name.lastIndexOf('/') != -1)
qual = name.substring(0, name.lastIndexOf('/')) + "/*";
// Edit only classes explicitly mentioned.
if (ONLY.size() > 0) {
skip = true;
// Only edit classes we explicitly don't name.
for (int i = 0; i < ONLY.size(); i++) {
String pkg = (String) ONLY.get(i);
if (name.equals(pkg) || qual.equals(pkg)) {
skip = false;
break;
}
}
}
// Don't edit classes we explicitly skip.
if (!skip) {
for (int i = 0; i < SKIP.size(); i++) {
String pkg = (String) SKIP.get(i);
if (name.equals(pkg) || qual.equals(pkg)) {
skip = true;
break;
}
}
}
if (skip) {
if (VERBOSE) {
System.out.println("Skipping " + c.getClassName());
}
// We're done with this class file, decrement its reference
// count
context.release(classFile);
return;
}
// Touch the output file first. That is, create the file, but make
// it empty, just to make sure we can create it.
// File outputDir = loader.outputDir();
if (VERBOSE) {
System.out.println("Optimizing " + c.getClassName());
}
// Finally, we can start playing with the methods...
Method[] methods = c.getMethods();
int numMethods = methods.length + 1;
;
int whichMethod = 0;
for (int j = 0; j < methods.length; j++) {
final MethodGen m;
try {
m = context.editMethod(methods[j], c.getClassName());
} catch (ClassFormatException ex) {
System.err.println(ex.getMessage());
continue;
}
if (TRACE) {
whichMethod++;
System.out
.println("Optimizing " + name + "." + m.getName()
+ " (method " + whichMethod + " of "
+ numMethods + ")");
}
if (METHOD != null) {
// A method name has been specified on the command line using
// -only-method.
boolean pass = true;
String t = m.getName() + m.getSignature();
if (t.equals(METHOD)) {
pass = false;
}
t = m.getName();
if (t.equals(METHOD)) {
pass = false;
}
if (pass) {
// This isn't the method we're looking for.
// Decrement its reference count.
context.release(methods[j], c.getClassName());
continue;
}
}
if (DEBUG) {
System.out.println(m);
}
if (m.isNative() || m.isAbstract()) {
// We can't edit native or abstract methods
context.release(methods[j], c.getClassName());
continue;
}
MethodBloater bloater = new MethodBloater(optimizationsToPerform);
bloater.bloatMethod(m, context);
}
if (ANNO) {
String s = "Optimized with: edu.purdue.cs.bloat.optimize.Main";
for (int i = 0; i < ARGS.length; i++) {
if (ARGS[i].indexOf(' ') >= 0 || ARGS[i].indexOf('\t') >= 0
|| ARGS[i].indexOf('\r') >= 0
|| ARGS[i].indexOf('\n') >= 0) {
s += " '" + ARGS[i] + "'";
} else {
s += " " + ARGS[i];
}
}
System.out.println(s);
}
try {
classFile = context.editClass(classFile.getClassName())
.getJavaClass();
} catch (ClassNotFoundException cnfe) {
}
try {
classFile.dump(targetFile);
} catch (java.io.IOException io) {
System.out.println("An error occured whilst writing file: "
+ targetFile.getPath());
}
if (TRACE)
System.out.println(context.toString());
}
public static void dumpcode(MethodGen m) {
PrintWriter out = new PrintWriter(System.out, true);
StackHeightCounter shc = new StackHeightCounter(m);
out.println("Code for method " + m.getName() + m.getSignature());
InstructionList instructions = m.getInstructionList();
Iterator iter = instructions.iterator();
while (iter.hasNext()) {
Object obj = iter.next();
shc.handle((InstructionHandle) obj);
System.out
.println(" " + obj + " (sh: " + shc.height() + ")");
}
}
/*
* The following block of code is a version of buildOptimizationsToPerform
* that does not use OptimizationsBuilder. If you revert to this version,
* you will have to uncomment the last couple of lines of
* MethodBloater#doAnOptimization().
*
* private static void buildOptimizationsToPerform() {
* optimizationsToPerform = new ArrayList();
*
* if (COMPACT_ARRAY_INIT) optimizationsToPerform.add(new
* CompactArrayInitializer());
*
* optimizationsToPerform.add(new SSA());
*
* if ((! Tree.USE_STACK) && PROP) optimizationsToPerform.add(new
* ExprPropagation());
*
* if (DCE) optimizationsToPerform.add(new DeadCodeElimination());
*
* if (INFER) optimizationsToPerform.add(new TypeInference());
*
* if (NUMBER) optimizationsToPerform.add(new ValueNumbering());
*
* if (FOLD) optimizationsToPerform.add(new ValueFolding());
*
* if (PRE) optimizationsToPerform.add(new SSAPRE());
*
* if (FOLD) optimizationsToPerform.add(new ValueFolding());
*
* if (PROP) optimizationsToPerform.add(new ExprPropagation()); // make sure
* we've done at least one thing since the last DCE if (DCE && (INFER ||
* NUMBER || FOLD || PRE || PROP)) optimizationsToPerform.add(new
* DeadCodeElimination()); //doDeadCodeElimination(cfg, context); /* if
* (PERSIST) (new PersistentCheckElimination()).transform(cfg);
*/
/*
* if (DIVA) optimizationsToPerform.add(new InductionVarAnalyzer());
* //doInductionVarAnalysis(cfg, context);
*
* if (OPT_STACK_2) { optimizationsToPerform.add(new StackOpt());
* optimizationsToPerform.add(new SSA()); optimizationsToPerform.add(new
* DeadCodeElimination()); }
*
* if (CodeGenerator.OPT_STACK) { optimizationsToPerform.add(new
* StackOptimization()); }
*
* if (VERIFY) optimizationsToPerform.add(new VerifyCFG());
*
* optimizationsToPerform.add(new CodeGen()); optimizationsToPerform.add(new
* ConstantPoolSizePrinter()); optimizationsToPerform.add(new Peephole()); }
*/
public static void buildOptimizationsToPerform() {
OptimizationsBuilder builder = new OptimizationsBuilder();
builder.add(new SSA());
if ((!Tree.USE_STACK) && PROP)
builder.add(new ExprPropagation());
if (DCE)
builder.add(new DeadCodeElimination());
if (INFER)
builder.add(new TypeInference());
if (NUMBER)
builder.add(new ValueNumbering());
if (FOLD)
builder.add(new ValueFolding());
if (PRE)
builder.add(new SSAPRE());
if (FOLD)
builder.add(new ValueFolding());
if (PROP)
builder.add(new ExprPropagation());
// make sure we've done at least one thing since the last DCE
if (DCE && (INFER || NUMBER || FOLD || PRE || PROP))
builder.add(new DeadCodeElimination());
/*
* if (PERSIST) (new PersistentCheckElimination()).transform(cfg);
*/
if (DIVA)
builder.add(new InductionVarAnalyzer());
if (OPT_STACK_2) {
builder.add(new StackOpt());
builder.add(new SSA());
builder.add(new DeadCodeElimination());
}
RegisterAllocator alloc = new RegisterAllocator();
builder.add(alloc);
if (CodeGenerator.OPT_STACK) {
builder.add(new StackOptimization());
}
if (VERIFY)
builder.add(new VerifyCFG());
builder.add(new CodeGen(alloc));
// builder.add(new ConstantPoolSizePrinter());
builder.add(new Peephole());
optimizationsToPerform = builder.getList();
}
/**
* OptimizationsBuilder is a little utility class intended to simplify the
* creation of the list of optimizations. In particular, it will
* automatically add a VerifyCFG call after each optimization whenever we're
* in debug mode. This simplifies the creation of the list, and
* {@link MethodBloater#doAnOptimization(Optimization, MethodState)} too.
*
* @author Chris Bennetts
*
*/
static class OptimizationsBuilder {
private List _optimizations = new ArrayList();
public List getList() {
return _optimizations;
}
public OptimizationsBuilder add(Optimization opt) {
_optimizations.add(opt);
if (DEBUG)
_optimizations.add(new VerifyCFG());
return this;
}
}
}

@ -0,0 +1,31 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
CodeGen.class \
ConstantPoolSizePrinter.class \
Main.class \
MethodBloater.class \
MethodState.class \
Optimization.class
include ../class.mk

@ -0,0 +1,243 @@
/*
* Class: MethodBloater
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.bcel.generic.LocalVariableGen;
import org.apache.bcel.generic.CodeExceptionGen;
import org.apache.bcel.generic.MethodGen;
import edu.purdue.cs.bloat.context.BloatContext;
import edu.purdue.cs.bloat.util.Assert;
/**
* Performs BLOAT-ing on a method. A single MethodBloater object may be safely
* reused for multiple methods.
*
* Extra debugging information will be printed if the system property
* <tt>edu.purdue.cs.bloat.DEBUG</tt> is set to <tt>true</tt>.
*
* @author Chris Bennetts
*
*/
public class MethodBloater {
static DateFormat dateFormat = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.LONG);
static boolean DEBUG = "true".equals(System
.getProperty("edu.purdue.cs.bloat.DEBUG"));
List optimizationsToPerform;
/**
* Create a new MethodBloater.
*
* @param optimizationsToPerform
* The optimizations to be performed.
*/
public MethodBloater(List optimizationsToPerform) {
this.optimizationsToPerform = optimizationsToPerform;
}
/**
* BLOAT a single method. Creates the {@link MethodState method state},
* runs the optimizations, and commits any changes back to the context
* object.
* <p>
*
* Will return prematurely if there is a problem creating the control flow
* graph.
*/
public void bloatMethod(MethodGen methodGen, BloatContext context) {
try {
MethodBloater.printMethodGenInfo(methodGen);
MethodState state = new MethodState(methodGen, context);
if (state.controlFlowGraph() == null)
return;
performOptimizations(state);
state.commitChanges();
// ConstantPoolSizePrinter.print(state);
MethodBloater.printMethodGenInfo(methodGen);
} catch (IllegalArgumentException e) {
System.out.println(" NOTE: CFG did not verify while bloating "
+ methodGen.getName()
+ " after all optimizations. Exception: " + e);
e.printStackTrace();
} catch (Exception e) {
String msg = "** Exception while optimizing " + methodGen.getName()
+ methodGen.getSignature() + " of class "
+ methodGen.getClassName();
System.err.println(msg);
System.err.println(e.getMessage());
e.printStackTrace(System.err);
System.exit(1);
}
}
/**
* Performs all optimizations on the method.
*
* @param state
* The method to perform the optimizations on.
* @throws Exception
* Any exception that may be thrown by the optimizations.
*/
public void performOptimizations(MethodState state) throws Exception {
Assert.isNotNull(optimizationsToPerform);
Iterator it = optimizationsToPerform.iterator();
while (it.hasNext()) {
Optimization opt = (Optimization) it.next();
doAnOptimization(opt, state);
}
}
/**
* Print the trace message for an optimization.
*
* @see Optimization#traceMessage(String)
*/
private void printTraceMessage(Optimization o) {
if (!DEBUG)
return;
String dateString = dateFormat.format(new Date());
String message = o.traceMessage(dateString);
if (message != null)
System.out.println(message);
}
/**
* Print a debug message for an optimization. Called before the
* transformation is performed.
*
* @see Optimization#preDebugMessage()
*/
private void printPreDebugMessage(Optimization o) {
if (!DEBUG)
return;
String message = o.preDebugMessage();
if (message != null)
System.out.println(message);
}
/**
* Print a debug message for an optimization. Called after the
* transformation is performed.
*
* @see Optimization#postDebugMessage()
*/
private void printPostDebugMessage(Optimization o) {
if (!DEBUG)
return;
String message = o.postDebugMessage();
if (message != null)
System.out.println(message);
}
/**
* Apply an optimization to a method.
*
* @param optimization
* The optimization to be performed.
* @param state
* The method to perform the optimization on.
* @throws Exception
* Any exception thrown by the optimization.
*
* @see Optimization#transform(MethodState)
*/
private void doAnOptimization(Optimization optimization, MethodState state)
throws Exception {
printTraceMessage(optimization);
printPreDebugMessage(optimization);
optimization.transform(state);
printPostDebugMessage(optimization);
// FIXME: VerifyCFG can itself now be called as an Optimization.
// Use a Builder or something to encapsulate this bit of behaviour.
// This is currently implemented by Main.OptimizationsBuilder, and
// MainG2 allows it to just be inserted into the list of optimizations.
// if (DEBUG)
// VerifyCFG.verify(state.controlFlowGraph());
}
/**
* Print some debugging info about the MethodGen.
*/
static void printMethodGenInfo(MethodGen methodGen) {
if (!DEBUG)
return;
LocalVariableGen[] locals = null;
CodeExceptionGen[] excptns = null;
System.out.println("Method: " + methodGen);
System.out.println(methodGen.getMethod().getCode());
System.out.println();
locals = methodGen.getLocalVariables();
if (locals != null) {
System.out.println("LocalVariables: ");
for (int j = 0; j < locals.length; j++)
System.out.println(" " + locals[j]);
}
excptns = methodGen.getExceptionHandlers();
if (excptns != null) {
System.out.println("ExceptionHandlers: ");
for (int j = 0; j < excptns.length; j++)
System.out.println(" " + excptns[j]);
}
}
}

@ -0,0 +1,140 @@
/*
* Class: MethodState
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.generic.MethodGen;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.context.BloatContext;
/**
* MethodState encapsulates three related items for a method:
*
* <ul>
* <li>its MethodGen,</li>
* <li>its Control Flow Graph,</li>
* <li>its context.</li>
* </ul>
*
* These tend to be passed around and updated together, so it made sense to
* group them together.
*
* Note that this class has no &quot;setters&quot;. If they appear necessary,
* move the code that would need them in to this class, instead of taking the
* shortcut.
*
* @author Chris Bennetts
*
*/
public class MethodState {
private MethodGen _methodGen;
private FlowGraph _controlFlowGraph;
private BloatContext _context;
/**
* Create a new MethodState object. The control flow graph is generated
* automatically.
*/
public MethodState(MethodGen methodGen, BloatContext context) {
_methodGen = methodGen;
_context = context;
rebuildFlowGraph();
}
/**
* Obtain the MethodGen.
*/
public MethodGen methodGen() {
return _methodGen;
}
/**
* Obtain the control flow graph. In general, favour
* {@link #controlFlowGraph() controlFlowGraph()}.
*/
public FlowGraph cfg() {
return controlFlowGraph();
}
/**
* Obtain the control flow graph.
*/
public FlowGraph controlFlowGraph() {
return _controlFlowGraph;
}
/**
* Obtain the current context.
*/
public BloatContext context() {
return _context;
}
/**
* Rebuild the control flow graph. Use if it falls out of sync with the
* MethodGen.
*
*/
public void rebuildFlowGraph() {
try {
_controlFlowGraph = new FlowGraph(_methodGen);
} catch (ClassFormatException ex) {
System.err.println(ex.getMessage());
_context.release(_methodGen.getMethod(), _methodGen.getClassName());
_controlFlowGraph = null;
return;
}
_controlFlowGraph.initialize();
}
/**
* Commit changes to the method to the context.
*
*/
public void commitChanges() {
_context.commit(_methodGen);
}
}

@ -0,0 +1,90 @@
/*
* Class: Optimization
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.optimize;
/**
* Optimization provides a uniform interface to all transformations provided by
* BLOAT. As well as the transform() method, Optimization also specifies a
* number of trace/debug methods.
*
* There's no actual requirement for Optimizations to actually transform the
* code. It is perfectly acceptable to create "optimizations" that print some
* kind of debugging information without actually changing the method state.
*
* In addition to the four methods that this interface declares, all
* implementers must provide a public zero-argument constructor.
*
* @author Chris Bennetts
*
*/
public interface Optimization {
/**
* Perform the optimization.
*
* @param state
* @throws Exception
*/
void transform(MethodState state) throws Exception;
/**
* Print a trace message. Called before #preDebugMessage().
*
* @param dateString
* The current timestamp.
*
* @return
*/
String traceMessage(String dateString);
/**
* Print a debugging message. Called before #transform().
*
* @return
*/
String preDebugMessage();
/**
* Print a debugging message. Called after #transform().
*
* @return
*/
String postDebugMessage();
}

@ -0,0 +1,7 @@
<html>
<body>
<p>Contains a program that optimizes Java classes.</p>
</body>
</html>

@ -0,0 +1,50 @@
/*
* Class: ClassFormatException
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.reflect;
public class ClassFormatException extends RuntimeException {
// serialVersionUID is strongly recommended for all classes implementing
// Serializable
public static final long serialVersionUID = 1L;
public ClassFormatException(String msg) {
super(msg);
}
}

@ -0,0 +1,25 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
ClassFormatException.class\
include ../class.mk

@ -0,0 +1,14 @@
<html>
<body>
<p>Provides an abstract API for working with Java classfiles. In this
package, names and types are represent by indices into the constant
pool. Modifier flags, the constant pool, exception handlers, and
debugging information are also modeled directly in this package. The
classes and interfaces in this package exist to give an opaque and
abstract view of the underlying representation of the Java class.</p>
</body>
</html>

@ -0,0 +1,52 @@
/*
* Class: ComponentVisitor
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.ssa;
import java.util.*;
/**
* ComponentVisitor is used to visit the strongly connected components (SSC) of
* a control flow graph.
*
* @see SSAGraph
*/
public abstract class ComponentVisitor {
public abstract void visitComponent(List component);
}

@ -0,0 +1,29 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
PhiReturnStmt.class\
SSAConstructionInfo.class\
ComponentVisitor.class\
SSAGraph.class\
SSA.class
include ../class.mk

@ -0,0 +1,162 @@
/*
* Class: PhiReturnStmt
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.ssa;
import java.util.*;
import edu.purdue.cs.bloat.cfg.Subroutine;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
/**
* A PhiReturnStmt is placed at the return site of a subroutine. This is
* necessary because variables that are not referrenced inside a subroutine
* (finally block) retain their value. This is a problem for SSA when a variable
* is assigned to inside an exception handler. At the beginning of the finally
* block, there would be a merge of two occurrences of the variable (one from
* the the exception handler and another from the "outside world") and a phi
* function should be placed accordingly. If the type of the variable was
* changed inside the exception handler, the operands of phi function would be
* of different types and that would be bad. To avoid this situation
* PhiReturnStmt are placed before the next instruction to be executed after the
* subroutine has returned. Note that each PhiReturnStmt has only one operand
* that is the same variable as its target. The two variables will have
* different version numbers, however.
* <p>
* The following diagram demonstrates PhiReturnStmt:
*
* <pre>
* a1 = 1 a2 = 2
* b1 = 1 b2 = 2
* jsr jsr
* \ /
* \ /
* \ /
* *
* a3 = PhiJoinStmt(a1, a2)
* b3 = PhiJoinStmt(b1, b2)
* |
* b4 = 4 // b is defined in subrountine
* |
* ret
* *
* / \
* / \
* / \
* / \
* a4 = PhiReturnStmt(a3) a5 = PhiReturnStmt(a3)
* b5 = PhiReturnStmt(b4) b6 = PhiReturnStmt(b4)
* </pre>
*
* After transformation, the PhiReturnStmts will become
*
* <pre>
* a1 a2
* b4 b4
* </pre>
*
* The variable <tt>a</tt> is not modified in the subroutine, so it retains
* its value from before the jsr. The variable <tt>b</tt> is modified in the
* subroutine, so its value after the ret is the value it was assigned in the
* subroutine.
*/
class PhiReturnStmt extends PhiStmt {
final Subroutine sub;
final Expr operand;
/**
* Constructor.
*
* @param target
* Local variable to which the result of this phi statement is to
* be assigned.
* @param sub
* The subroutine from which we are returning.
*/
public PhiReturnStmt(VarExpr target, Subroutine sub) {
super(target);
this.sub = sub;
this.operand = (VarExpr) target.clone();
operand.setParent(this);
operand.setDef(null);
}
public void visitForceChildren(TreeVisitor visitor) {
operand.visit(visitor);
}
public void visit(TreeVisitor visitor) {
visitChildren(visitor);
}
/**
* Returns the subroutine associated with this <tt>PhiReturnStmt</tt>.
*/
public Subroutine sub() {
return sub;
}
/**
* Returns a collection containing the operands to the phi statement. In
* this case the collection contains the one operand.
*/
public Collection operands() {
ArrayList v = new ArrayList();
v.add(operand);
return v;
}
/**
* Returns the operand of this <tt>PhiReturnStmt</tt> statement. A
* <tt>PhiReturnStmt</tt> has only one operand because the block that
* begins an exception handler may have only one incoming edge (critical
* edges were split).
*/
public Expr operand() {
return operand;
}
public String toString() {
return "" + target() + " := Phi-Return(" + operand + ", " + sub + ")";
}
}

@ -0,0 +1,594 @@
/*
* Class: SSA
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.ssa;
import java.util.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.cfg.Handler;
import edu.purdue.cs.bloat.cfg.Subroutine;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.tree.DefExpr;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
/**
* Compute the SSA form of the control flow graph and build FUD chains.
* <p>
* The SSA algorithm is from:
*
* <pre>
* R. Cytron, J. Ferrante J, B. K. Rosen, M. N. Wegman, and F. K. Zadeck,
* &quot;Efficiently Computing Static Single Assignment Form and the Control
* Dependence Graph&quot;, TOPLAS, 13(4): 451-490, October 1991.
* </pre>
*
* <p>
* I made modifications to the algorithm to compute FUD chains and to run the
* algorithm separately for each variable similar to the SSAPRE algorithm.
* Making a separate pass for each variable allows variables to be added
* incrementally.
*/
public class SSA implements Optimization {
public static boolean DEBUG = false;
public void transform(MethodState state) {
transform(state.controlFlowGraph());
}
/**
* Transforms a control flow graph into Single Static Assignment (SSA) form.
* First, the CFG is traversed and a list of all variables (both local and
* stack) eligible for SSA renaming is compiled. Variables are represented
* by instances of <tt>SSAConstructionInfo</tt>. Each of these variables
* is then transformed.
*
* @see #transform
* @see SSAConstructionInfo
*/
private void transform(FlowGraph cfg) {
Iterator e = collectVars(cfg);
while (e.hasNext()) {
SSAConstructionInfo info = (SSAConstructionInfo) e.next();
transform(cfg, info);
}
}
/**
* Performs the actions necessary to convert a CFG into SSA form with
* respect to one variable. The variable's information is stored in the
* <tt>SSAConstructionInfo</tt>.
*/
public void transform(FlowGraph cfg, SSAConstructionInfo info) {
if (DEBUG) {
System.out.println("transforming " + info.prototype + " ("
+ info.prototype.type() + ")");
}
placePhiFunctions(cfg, info);
rename(cfg, info);
insertCode(cfg, info);
}
/**
* Visits the nodes in a control flow graph and constructs
* <tt>SSAConstructionInfo</tt> objects for each variable in the CFG.
* Returns the <tt>SSAConstructionInfo</tt>s for the variables in the
* CFG.
*/
private Iterator collectVars(final FlowGraph cfg) {
// SSAConstructionInfo objects for cfg
final Map infos = new LinkedHashMap();
cfg.visit(new TreeVisitor() {
// Visit all statements in the CFG. Remove any pre-existing
// PhiStmts.
public void visitTree(Tree tree) {
Iterator iter = tree.stmts().iterator();
while (iter.hasNext()) {
Stmt stmt = (Stmt) iter.next();
if (stmt instanceof PhiStmt) {
iter.remove();
} else {
stmt.visit(this);
}
}
}
// Recall that VarExprs represent variables. If we have not
// already created a SSAConstructionInfo for a variable
// (VarExpr), do so. Make note of the fact that this is a real
// occurrence of the variable.
public void visitVarExpr(VarExpr expr) {
expr.visitChildren(this);
expr.setDef(null);
Object key = expr.comparator();
SSAConstructionInfo info = (SSAConstructionInfo) infos.get(key);
if (info == null) {
info = new SSAConstructionInfo(cfg, expr);
infos.put(key, info);
}
info.addReal(expr);
}
});
return infos.values().iterator();
}
/**
* Places phi statements at the appropriate locations in the CFG. This
* implementation only places phi functions for variables that are live on
* entry to at least one block. That is, if a variable is only used within
* one block, we don't bother searching for a place to put phi functions for
* it.
*
* @param cfg
* The CFG in which phi functions are placed.
* @param info
* The variable for which phi functions will be placed.
*/
private void placePhiFunctions(FlowGraph cfg, SSAConstructionInfo info) {
if (DEBUG) {
System.out.println("Placing phi-functions for " + info);
}
// Phis are only placed for variables which are live on entry to
// at least one block.
//
// This is the semi-pruned form described in "Practical
// Improvements to the Construction and Destruction of Static
// Single Assignment Form" by Briggs, Cooper, Harvey, Simpson
//
// Blocks in which the variable in the SSAConstructionInfo is
// defined. That is, variables that are defined in this block.
BitSet killed = new BitSet(cfg.size());
// Is the variable used in more than one block?
boolean nonLocal = false;
Iterator reals = info.reals().iterator();
// Look at all real (not in phi statement) occurrences of the
// variable in the SSAConstructionInfo. Determine which variables
// are live on entry to some basic block (i.e. "non-local"). If
// a variable is not live on entry to some basic block, it is only
// used within the block in which it is defined, so don't bother
// adding a phi statement for it.
while (reals.hasNext()) {
VarExpr real = (VarExpr) reals.next();
Block block = real.block(); // Block in which variable occurs
if (real.isDef()) {
killed.set(cfg.preOrderIndex(block));
} else if (!killed.get(cfg.preOrderIndex(block))) {
// There is a use of the variable as an operand that is not
// defined in the block in which it occurs. Therefore, the
// variable is non-local.
nonLocal = true;
break;
}
}
if (!nonLocal) {
return;
}
// We've decided that this variable is used in multiple blocks,
// so go ahead and place phi functions for it.
// Iterate over all of the catch blocks (blocks that begin an
// exception handler) in the CFG and instert PhiCatchStmts where
// appropriate.
Iterator catchBlocks = cfg.catchBlocks().iterator();
while (catchBlocks.hasNext()) {
Block block = (Block) catchBlocks.next();
info.addCatchPhi(block);
info.addDefBlock(block);
}
// Iterate over all of the subroutines (finally blocks) and insert
// PhiReturnStmts where appropriate.
Iterator subs = cfg.subroutines().iterator();
while (subs.hasNext()) {
Subroutine sub = (Subroutine) subs.next();
info.addRetPhis(sub);
Iterator paths = sub.paths().iterator();
while (paths.hasNext()) {
Block[] path = (Block[]) paths.next();
info.addDefBlock(path[1]);
}
}
// Now we add real phi functions to the CFG. Phi functions are
// placed at the (blocks in the) iterated dominance fontier of each
// of the blocks containing a definition of the variable.
Iterator df = cfg.iteratedDomFrontier(info.defBlocks()).iterator();
while (df.hasNext()) {
Block block = (Block) df.next();
// Don't place phi-statements in the exit block because one of
// the operands will always have a null definition.
if (block != cfg.sink())
info.addPhi(block);
}
}
/**
* If the block resides in a protected region and there is a
* <tt>PhiCatchStmt</tt> for the variable in question in the handler of
* the exception thrown by the protected region (meaning that the variable
* is used in the protected region), the variable becomes an operand to the
* <tt>PhiCatchStmt</tt>.
*
* @param info
* The variable (LocalExpr) that we're dealing with
* @param block
* The block in a potentially protected region. If the block is
* indeed in a protected region, the occurrence of the the
* variable represented by info becomes an operand to the
* PhiCatchStmt at the beginning of the protected region's
* handler.
* @param def
* The defining occurrence of the variable stored in info.
*/
private void addCatchPhiOperands(SSAConstructionInfo info, Block block,
LocalExpr def) {
Iterator handlers = block.graph().handlers().iterator();
// Iterate over all of the exception handlers in the CFG. If
// the block we are dealing with is a protected block (that is,
// is inside a try block), then the variable represented by info
// becomes an operand to the PhiCatchStmt residing at the
// beginning of the protected block's handler.
while (handlers.hasNext()) {
Handler handler = (Handler) handlers.next();
if (handler.protectedBlocks().contains(block)) {
PhiCatchStmt phi = (PhiCatchStmt) info.phiAtBlock(handler
.catchBlock());
if (phi != null && !phi.hasOperandDef(def)) {
LocalExpr operand = (LocalExpr) info.prototype.clone();
operand.setDef(def); // ???
phi.addOperand(operand);
}
}
}
}
/**
* The actual renamining is done by the search method. This method just
* takes care of <Tt>PhiReturnStmts</tt>.
*/
private void rename(FlowGraph cfg, SSAConstructionInfo info) {
search(cfg, info, null, cfg.source());
// Eliminate PhiReturns by replacing their uses with the defs live
// at the end of the returning sub or live on the same path on entry
// to the sub (if the variable did not occur in the subroutine).
// Examine each PhiReturnStmt in the CFG. Recall that
// PhiReturnStmts are "inserted" at blocks that begin exceptions
boolean changed = true;
while (changed) {
changed = false;
Iterator subs = cfg.subroutines().iterator();
while (subs.hasNext()) {
Subroutine sub = (Subroutine) subs.next();
Iterator paths = sub.paths().iterator();
PhiJoinStmt entry = (PhiJoinStmt) info.phiAtBlock(sub.entry());
if (entry == null) {
// If there was no PhiJoinStmt for the variable in the
// subroutine, who cares? We don't.
continue;
}
while (paths.hasNext()) {
Block[] path = (Block[]) paths.next();
PhiReturnStmt ret = (PhiReturnStmt) info
.phiAtBlock(path[1]);
if (ret != null) {
DefExpr def = ret.operand().def();
if (def != entry.target()) {
// If the operand of the PhiReturnStmt is
// different from
// the new SSA variable defined by the
// PhiCatchStmt at
// the beginning of the subroutine, then the
// variable
// was defined in the subroutine, so the operand
// to the
// PhiReturnStmt is the correct SSA variable.
// This is
// like the variable "b" in figure 3.5 in Nate's
// Thesis.
continue;
}
// Replace all uses of the target of the PhiReturnStmt
// with the SSA variable corresponding to the block in
// which the jsr occured. This is like variable "a" in
// figure 3.5 in Nate's Thesis.
def = ((VarExpr) entry.operandAt(path[0])).def();
Iterator uses = ret.target().uses().iterator();
while (uses.hasNext()) {
VarExpr use = (VarExpr) uses.next();
use.setDef(def);
}
// The PhiReturnStmt is no longer needed
info.removePhiAtBlock(path[1]);
changed = true;
}
}
}
}
Iterator subs = cfg.subroutines().iterator();
// Examine any remaining PhiReturnStmts. Replace all uses of the
// target of the PhiReturnStmt with its operand.
while (subs.hasNext()) {
Subroutine sub = (Subroutine) subs.next();
Iterator paths = sub.paths().iterator();
while (paths.hasNext()) {
Block[] path = (Block[]) paths.next();
PhiReturnStmt ret = (PhiReturnStmt) info.phiAtBlock(path[1]);
if (ret != null) {
DefExpr def = ret.operand().def();
Iterator uses = ret.target().uses().iterator();
while (uses.hasNext()) {
VarExpr use = (VarExpr) uses.next();
use.setDef(def);
}
info.removePhiAtBlock(path[1]);
}
}
}
}
/**
* Does the actual renaming. It keeps track of the most recent occurrence of
* an (SSA numbered) variable and recalculates the definitions of variables
* appropriately.
*
* @param info
* SSAConstructionInfo representing the variable being converted
* into SSA form.
* @param top
* "Top" of the variable stack for the variable in question. Each
* variable has a "stack" associated with it. The top of the
* stack contains the current SSA name of the variable. It can
* also be thought of as the "most recent definition" of the
* variable.
* @param block
* Basic block in which the variable is being renamed.
*/
private void search(FlowGraph cfg, SSAConstructionInfo info, VarExpr top,
Block block) {
if (DEBUG) {
System.out.println("renaming " + info.prototype + " in " + block);
}
// If appropriate, add top as an operand of a PhiCatchStmt
if (top instanceof LocalExpr) {
addCatchPhiOperands(info, block, (LocalExpr) top);
}
// First handle any phi in the block.
PhiStmt phi = info.phiAtBlock(block);
if (phi != null) {
top = phi.target();
if (top instanceof LocalExpr) {
addCatchPhiOperands(info, block, (LocalExpr) top);
}
}
// If the block in which the variable is being renamed begins an
// exception handler and we're dealing with a stack variable, then
// there is no most recent definition of the variable because the
// stack is cleared when an exception is handled. I dunno.
if (cfg.catchBlocks().contains(block)
&& info.prototype instanceof StackExpr) {
if (DEBUG) {
System.out.println(" Killing TOS at " + block);
}
// The operand stack is popped down to 0 at catch blocks.
top = null;
}
Iterator e = info.realsAtBlock(block).iterator();
// Examine each occurrence of the variable in the block of
// interest. When we encounter a definition of the variable, make
// that definition to the most recent SSA variable (top). For
// each use, make this most recent SSA variable be its defining
// expression.
while (e.hasNext()) {
VarExpr real = (VarExpr) e.next();
if (real.isDef()) {
real.setDef(null);
top = real; // A definition means a new SSA variable
if (top instanceof LocalExpr) {
addCatchPhiOperands(info, block, (LocalExpr) top);
}
if (DEBUG) {
System.out.println(" TOS = " + top);
}
} else {
// Make sure that the variable is defined somewhere else
// (somewhere that we have already seen).
Assert.isTrue(top != null, "Null def for " + real);
real.setDef(top);
}
}
Iterator succs = cfg.succs(block).iterator();
// Examine all successors of the block in question. If the
// successor contains a PhiJoinStmt for the variable, then set the
// operand corresponding to the block to be defined by the most
// recent SSA variable. Similarly for a PhiReturnStmt.
while (succs.hasNext()) {
Block succ = (Block) succs.next();
PhiStmt succPhi = info.phiAtBlock(succ);
if (succPhi instanceof PhiJoinStmt) {
PhiJoinStmt f = (PhiJoinStmt) succPhi;
VarExpr operand = (VarExpr) f.operandAt(block);
operand.setDef(top);
} else if (succPhi instanceof PhiReturnStmt) {
PhiReturnStmt f = (PhiReturnStmt) succPhi;
VarExpr operand = (VarExpr) f.operand();
operand.setDef(top);
}
// Adjust the operands of any PhiCatchStmts if the sucessor node
// is protected.
if (top instanceof LocalExpr) {
addCatchPhiOperands(info, succ, (LocalExpr) top);
}
}
Iterator children = cfg.domChildren(block).iterator();
// Visit the children in the dominator tree. Keep the same most
// recent SSA variable (top).
while (children.hasNext()) {
Block child = (Block) children.next();
search(cfg, info, top, child);
}
}
/**
* Iterates over the blocks in the CFG and inserts the phi statement
* associated with that block. Up until this point, the phi statement is
* only maintained in SSAConstructionInfo. Note that the phi statement
* cannot be a return phi.
*
* @param cfg
* The CFG into which to insert phi statements.
* @param info
* Represents the variable whose phi statements we are inserting.
*
* @see PhiReturnStmt
*/
private void insertCode(FlowGraph cfg, SSAConstructionInfo info) {
Iterator blocks = cfg.nodes().iterator();
while (blocks.hasNext()) {
Block block = (Block) blocks.next();
PhiStmt phi = info.phiAtBlock(block);
if (phi != null) {
Assert.isFalse(phi instanceof PhiReturnStmt);
block.tree().prependStmt(phi);
}
}
}
public String traceMessage(String dateString) {
return " Transforming to SSA: " + dateString;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
}

@ -0,0 +1,296 @@
/*
* Class: SSAConstructionInfo
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.ssa;
import java.util.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.cfg.Subroutine;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
/**
* <tt>SSAConstructionInfo</tt> contains information needed to convert a CFG
* into SSA form. Each variable (VarExpr) has an SSAConstructionInfo associated
* with it. Each <tt>SSAConstructionInfo</tt> keeps track of information such
* as the <tt>PhiStmt</tt>s that define copies of the variable, the
* <tt>Block</tt>s in which the variable is defined, and the occurrences
* (uses) of the variable in both phi and non-phi statements. Note that no
* <tt>PhiStmt</tt> is really inserted into a basic block. We just keep track
* of the mapping. It should also be noted that once a phi statement for a given
* variable is "inserted" into a block, no other phi statement for that variable
* is inserted. Thus, the order of insertion determines the precedence of the
* phi statements: <tt>PhiReturnStmt</tt> &gt; <tt>PhiCatchStmt</tt> &gt;
* <tt>PhiJoinStmt</tt>.
*
* <p>
*
* Additionally, <tt>SSAConstruction</tt> has methods to insert various
* flavors of <tt>PhiStmt</tt>s whose targets are the variable associated
* with the <tt>SSAConstruction</tt> into <tt>Block</tt>s.
*
* @see SSA
* @see PhiStmt
* @see PhiCatchStmt
* @see PhiJoinStmt
* @see PhiReturnStmt
*/
public class SSAConstructionInfo {
FlowGraph cfg; // The cfg we're converting into SSA form
VarExpr prototype; // The variable we're converting into SSA form
LinkedList[] reals; // The real (non-phi) occurrences associated
// with a given node (block)
LinkedList allReals; // All the real occurrences of the variable
PhiStmt[] phis; // Phi statement associated with a given block
Set defBlocks; // Blocks in which variable is defined
/**
* Constructor.
*
* @param cfg
* The control flow graph that is being converted to SSA form.
* @param expr
* A variable in the CFG on which SSA analysis is being done.
*/
public SSAConstructionInfo(FlowGraph cfg, VarExpr expr) {
this.cfg = cfg;
prototype = (VarExpr) expr.clone();
prototype.setDef(null);
reals = new LinkedList[cfg.size()];
allReals = new LinkedList();
defBlocks = new LinkedHashSet();
phis = new PhiStmt[cfg.size()];
}
/**
* Returns the program variable associated with this
* <tt>SSAConstructionInfo</tt>.
*/
public VarExpr prototype() {
return prototype;
}
/**
* Makes note of a <tt>Block</tt> in which the variable is defined by a
* <tt>PhiStmt</tt>.
*/
public void addDefBlock(Block block) {
defBlocks.add(block);
}
/**
* Returns the phi statement for the variable represented by this
* SSAConstructionInfo at a given block in the CFG.
*/
public PhiStmt phiAtBlock(Block block) {
return phis[cfg.preOrderIndex(block)];
}
/**
* Removes the phi statement for this variable at a given block.
*/
public void removePhiAtBlock(Block block) {
PhiStmt phi = phis[cfg.preOrderIndex(block)];
if (phi != null) {
if (SSA.DEBUG) {
System.out.println(" removing " + phi + " at " + block);
}
phi.cleanup();
phis[cfg.preOrderIndex(block)] = null;
}
}
/**
* Adds a <tt>PhiJoinStmt</tt> for the variable represented by this
* <tt>SSAConstructionInfo</tt> to a given <tt>Block</tt>.
*/
public void addPhi(Block block) {
if (phis[cfg.preOrderIndex(block)] != null) {
return;
}
VarExpr target = (VarExpr) prototype.clone();
PhiJoinStmt phi = new PhiJoinStmt(target, block);
phis[cfg.preOrderIndex(block)] = phi;
if (SSA.DEBUG) {
System.out.println(" place " + phi + " in " + block);
}
}
/**
* Adds a <tt>PhiReturnStmt</tt> to all of the <tt>Block</tt>s that are
* executed upon returning from a given <tt>Subroutine</tt>.
*
* @see PhiReturnStmt
* @see Subroutine#paths
*/
public void addRetPhis(Subroutine sub) {
Iterator paths = sub.paths().iterator();
while (paths.hasNext()) {
Block[] path = (Block[]) paths.next();
addRetPhi(sub, path[1]);
}
}
/**
* Inserts a <tt>PhiCatchStmt</tt> (whose target is the variable
* represented by this <tt>SSAConstructionInfo</tt>) into a given
* <tt>Block</tt>.
*
* @see PhiCatchStmt
*/
public void addCatchPhi(Block block) {
if (phis[cfg.preOrderIndex(block)] != null) {
return;
}
if (prototype instanceof LocalExpr) {
LocalExpr target = (LocalExpr) prototype.clone();
PhiCatchStmt phi = new PhiCatchStmt(target);
phis[cfg.preOrderIndex(block)] = phi;
if (SSA.DEBUG) {
System.out.println(" place " + phi + " in " + block);
}
}
}
/**
* Adds a <tt>PhiReturnStmt</tt> associated with a given
* <tt>Subroutine</tt>. The <tt>PhiReturnStmt</tt> is placed in a given
* block.
*
* @see PhiReturnStmt
*/
private void addRetPhi(Subroutine sub, Block block) {
if (phis[cfg.preOrderIndex(block)] != null) {
return;
}
VarExpr target = (VarExpr) prototype.clone();
PhiReturnStmt phi = new PhiReturnStmt(target, sub);
phis[cfg.preOrderIndex(block)] = phi;
if (SSA.DEBUG) {
System.out.println(" place " + phi + " in " + block);
}
}
/**
* Notes a real occurrence (that is, a use that is not an operand to a phi
* statement) of the variable represented by this
* <tt>SSAConstructionInfo</tt>.
*
* @see PhiStmt
*/
public void addReal(VarExpr real) {
if (real.stmt() instanceof PhiStmt) {
return;
}
Block block = real.block();
if (real.isDef()) {
defBlocks.add(block);
}
Assert.isTrue(block != null, real + " not in a " + block);
LinkedList l = reals[cfg.preOrderIndex(block)];
if (l == null) {
l = new LinkedList();
reals[cfg.preOrderIndex(block)] = l;
}
l.add(real);
allReals.add(real);
}
/**
* Returns all of the real occurrences of this variable.
*/
public Collection reals() {
return allReals;
}
/**
* Returns all of the real occurrences of this variable in a given block.
*/
public Collection realsAtBlock(Block block) {
LinkedList l = reals[cfg.preOrderIndex(block)];
if (l == null) {
l = new LinkedList();
reals[cfg.preOrderIndex(block)] = l;
}
return l;
}
/**
* Returns the Blocks containing a definition of the variable represented by
* this SSAConstruction info.
*/
public Collection defBlocks() {
return defBlocks;
}
}

@ -0,0 +1,731 @@
/*
* Class: SSAGraph
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.ssa;
import java.util.*;
import java.io.*;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.tree.CheckExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
/**
* The SSA graph (also called the value graph) represents the nesting of
* expression in a control flow graph. Each node in the SSA graph represents an
* expression. If the expression is a definition, the it is labeled with the
* variable it defines. Each node has directed edges to the nodes representing
* its operands.
*
* <p>
*
* <tt>SSAGraph</tt> is a representation of the definitions found in a CFG in
* the following form: Each node in the graph is an expression that defines a
* variable (a <tt>VarExpr</tt>, <tt>PhiStmt</tt>, or a
* <tt>StackManipStmt</tt>). Edges in the graph point to the nodes whose
* expressions define the operands of the expression in the source node.
*
* <p>
*
* This class is used primarily get the strongly connected components of the SSA
* graph in support of value numbering and induction variable analysis.
*
* <p>
*
* Nate warns: Do not modify the CFG while using the SSA graph! The effects of
* such modification are undefined and will probably lead to nasty things
* occuring.
*
* @see edu.purdue.cs.bloat.trans.ValueNumbering ValueNumbering
*/
public class SSAGraph {
public static boolean DEBUG = false;
FlowGraph cfg;
LinkedHashMap equiv; // A mapping between a Node and all its equivalent
// Nodes
/**
* Grumble.
*/
public SSAGraph(FlowGraph cfg, boolean useless) {
this(cfg);
}
/**
* Constructor. Traverse the control flow graph and determines which Nodes
* are of an equivalent Type.
*
* @param cfg
* The control flow graph to examine
*/
public SSAGraph(FlowGraph cfg) {
this.cfg = cfg;
this.equiv = new LinkedHashMap();
cfg.visit(new TreeVisitor() {
// The CheckExpr and the Expr is checks are equivalent.
public void visitCheckExpr(CheckExpr expr) {
expr.visitChildren(this);
makeEquiv(expr, expr.expr());
}
// The target of the PhiStmt and the PhiStmt are equivalent
public void visitPhiStmt(PhiStmt stmt) {
stmt.visitChildren(this);
makeEquiv(stmt.target(), stmt);
}
// The use of a variable and its defining variable are
// equivalent
public void visitVarExpr(VarExpr expr) {
if (!expr.isDef()) {
VarExpr def = (VarExpr) expr.def();
if (def != null) {
makeEquiv(expr, def);
}
}
}
// With StackManipStmts the stack slot (StackExpr) after the
// StackManipStmt is equivalent to its corresponding slot before
// the StackManipStmt.
public void visitStackManipStmt(StackManipStmt stmt) {
StackExpr[] target = stmt.target();
StackExpr[] source = stmt.source();
switch (stmt.kind()) {
case StackManipStmt.SWAP:
// 0 1 -> 1 0
Assert.isTrue(source.length == 2 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0 });
break;
case StackManipStmt.DUP:
// 0 -> 0 0
Assert.isTrue(source.length == 1 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 0, 0 });
break;
case StackManipStmt.DUP_X1:
// 0 1 -> 1 0 1
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
break;
case StackManipStmt.DUP_X2:
if (source.length == 3) {
// 0 1 2 -> 2 0 1 2
Assert.isTrue(source.length == 3 && target.length == 4,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 2, 0, 1, 2 });
} else {
// 0-1 2 -> 2 0-1 2
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
case StackManipStmt.DUP2:
if (source.length == 2) {
// 0 1 -> 0 1 0 1
Assert.isTrue(target.length == 4, "Illegal statement: "
+ stmt);
manip(source, target, new int[] { 0, 1, 0, 1 });
} else {
// 0-1 -> 0-1 0-1
Assert.isTrue(source.length == 1 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 0, 0 });
}
break;
case StackManipStmt.DUP2_X1:
if (source.length == 3) {
// 0 1 2 -> 1 2 0 1 2
Assert.isTrue(target.length == 5, "Illegal statement: "
+ stmt);
manip(source, target, new int[] { 1, 2, 0, 1, 2 });
} else {
// 0 1-2 -> 1-2 0 1-2
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
case StackManipStmt.DUP2_X2:
if (source.length == 4) {
// 0 1 2 3 -> 2 3 0 1 2 3
Assert.isTrue(target.length == 6, "Illegal statement: "
+ stmt);
manip(source, target, new int[] { 2, 3, 0, 1, 2, 3 });
} else if (source.length == 3) {
if (target.length == 5) {
// 0-1 2 3 -> 2 3 0-1 2 3
manip(source, target, new int[] { 1, 2, 0, 1, 2 });
} else {
// 0 1 2-3 -> 2-3 0 1 2-3
Assert.isTrue(target.length == 4,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 2, 0, 1, 2 });
}
} else {
// 0-1 2-3 -> 2-3 0-1 2-3
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
}
stmt.visitChildren(this);
}
// Determines equivalence of the StackExprs invovled in a
// StackManipStmt. Recall that StackManipStmt are things like
// the dup and swap instructions. So, elements (StackExprs) of
// the "new" stack will be equivalent to elements of the "old"
// stack. The s array defines the transformation.
private void manip(StackExpr[] source, StackExpr[] target, int[] s) {
for (int i = 0; i < s.length; i++) {
makeEquiv(target[i], source[s[i]]);
}
}
// The StoreExpr is equivalent to the expression being stored.
public void visitStoreExpr(StoreExpr expr) {
expr.visitChildren(this);
makeEquiv(expr, expr.expr());
if (expr.target() instanceof VarExpr) {
makeEquiv(expr.target(), expr.expr());
}
}
});
}
/**
* Returns the <tt>FlowGraph</tt> that this <tt>SSAGraph</tt> is built
* around.
*/
public FlowGraph cfg() {
return (this.cfg);
}
/**
* Returns a set of nodes whose value is equivalent to a given node. For
* example, the LHS and RHS of an assignment are equivalent. As are all
* local variables with the same definition.
*/
public Set equivalent(Node node) {
Set s = (Set) equiv.get(node);
if (s == null) {
s = new LinkedHashSet(1);
s.add(node); // A node is equivalent to itself
equiv.put(node, s);
}
return s;
}
/**
* Makes node1 equivalent to node2 by adding the equivlance Set of node2 to
* the equivalance Set of node1, and vice versa.
*/
void makeEquiv(Node node1, Node node2) {
Set s1 = equivalent(node1);
Set s2 = equivalent(node2);
if (s1 != s2) {
s1.addAll(s2);
Iterator iter = s2.iterator();
while (iter.hasNext()) {
Node n = (Node) iter.next();
equiv.put(n, s1);
}
}
}
/**
* Returns the children (that is, the operands) of a given Node in the SSA
* Graph.
*/
public List children(Node node) {
final ArrayList c = new ArrayList();
if (node instanceof StoreExpr) {
StoreExpr store = (StoreExpr) node;
// Add the grand children of RHS. The RHS is equivalent to
// this node.
store.expr().visitChildren(new TreeVisitor() {
public void visitNode(Node node) {
c.add(node);
}
});
// The LHS is equivalent to this node if it is a VarExpr and not
// a child.
if (!(store.target() instanceof VarExpr)) {
c.add(store.target());
}
} else if (node instanceof PhiStmt) {
PhiStmt phi = (PhiStmt) node;
c.addAll(phi.operands());
} else {
node.visitChildren(new TreeVisitor() {
public void visitNode(Node node) {
c.add(node);
}
});
}
return c;
}
/**
* Returns the Sets of Nodes whose values are equivalent.
*/
public Collection equivalences() {
return equiv.values();
}
class Count {
int value = 0;
}
/**
* Calculates the strongly connected components (SCC) of the SSA graph. SSCs
* are represented by a List of <tt>Node</tt>s. The SCCs are then visited
* by the ComponentVistor.
*/
public void visitComponents(final ComponentVisitor visitor) {
// Number the nodes reverse post order (i.e. topological order).
final Count count = new Count();
final List postOrder = cfg.postOrder();
ListIterator iter = postOrder.listIterator(postOrder.size());
// Perform a depth-first ordering of the nodes in the CFG to give
// each node a unique identifier. This is accomplished by
// visiting the blocks in the CFG in post-order and numbering the
// Nodes in the block's expression Tree in depth-first order.
while (iter.hasPrevious()) {
Block block = (Block) iter.previous();
block.visit(new TreeVisitor() {
public void visitTree(Tree tree) {
tree.visitChildren(this);
}
public void visitNode(Node node) {
node.visitChildren(this);
node.setKey(count.value++);
}
});
}
// Build the (strongly connected) components and call
// visitor.visitComponent for each.
cfg.visit(new TreeVisitor() {
ArrayList stack = new ArrayList();
BitSet onStack = new BitSet(count.value + 1);
int[] low = new int[count.value + 1];
int[] dfs = new int[count.value + 1];
int dfsNumber = 1;
Node parent; // Parent in the SSA graph
// Visit the blocks in the CFG in reverse postorder
public void visitFlowGraph(FlowGraph cfg) {
ListIterator e = postOrder.listIterator(postOrder.size());
while (e.hasPrevious()) {
Block block = (Block) e.previous();
block.visit(this);
}
}
public void visitTree(Tree tree) {
parent = null;
tree.visitChildren(this);
}
// This method is essentially Figure 4.6 in Taylor Simpson's PhD
// Thesis: www.cs.rice.edu/~lts. The implementation is a little
// funky, though, because someone wanted to use visitors.
// Grumble.
public void visitNode(Node node) {
int dfn = dfs[node.key()];
// System.out.println("visit " + node + " key=" + node.key() +
// " dfn=" + dfn);
if (dfn == 0) {
// The node in question has not yet been visited. Assign
// it
// the next dfNumber and add it to the stack. Mark all
// nodes that are equivalent to the node in question as
// being visited.
dfn = dfsNumber++;
low[dfn] = dfn;
stack.add(node);
onStack.set(dfn);
Iterator equiv = equivalent(node).iterator();
while (equiv.hasNext()) {
Node e = (Node) equiv.next();
dfs[e.key()] = dfn;
}
// Again examine each node, e, equivalent to the node in
// question. Then recursively visit the children of e in
// the SSA Graph.
Node grandParent = parent;
parent = node;
equiv = equivalent(node).iterator();
while (equiv.hasNext()) {
Node e = (Node) equiv.next();
Iterator children = children(e).iterator();
while (children.hasNext()) {
Node child = (Node) children.next();
child.visit(this);
}
}
parent = grandParent; // Restore true parent
// Now we finally get to the point where we can
// construct a
// strongly connected component. Pop all of the nodes
// off
// the stack until the node in question is reached.
if (low[dfn] == dfn) {
ArrayList scc = new ArrayList();
while (!stack.isEmpty()) {
Node v = (Node) stack.remove(stack.size() - 1);
onStack.clear(dfs[v.key()]);
scc.addAll(equivalent(v));
if (v == node) {
break;
}
}
// Sort the nodes in the SCC by their reverse
// post order numbers.
Collections.sort(scc, new Comparator() {
public int compare(Object a, Object b) {
int ka = ((Node) a).key();
int kb = ((Node) b).key();
return ka - kb;
}
});
if (DEBUG) {
System.out.print("SCC =");
Iterator e = scc.iterator();
while (e.hasNext()) {
Node v = (Node) e.next();
System.out.print(" " + v + "{" + v.key() + "}");
}
System.out.println();
}
// Visit the SCC with the visitor that was passed in.
visitor.visitComponent(scc);
}
if (parent != null) {
int parentDfn = dfs[parent.key()];
low[parentDfn] = Math.min(low[parentDfn], low[dfn]);
}
} else {
// We've already visited the node in question
if (parent != null) {
int parentDfn = dfs[parent.key()];
// (parent, node) is either a cross edge or a back edge.
if (dfn < parentDfn && onStack.get(dfn)) {
low[parentDfn] = Math.min(low[parentDfn], dfn);
}
}
}
}
});
}
/**
* Visits the strongly connected component that contains a given
* <tt>Node</tt>.
*/
public void visitComponent(final Node startNode,
final ComponentVisitor visitor) {
// Number the nodes reverse post order (i.e. topological order).
final Count count = new Count();
final List postOrder = cfg.postOrder();
ListIterator iter = postOrder.listIterator(postOrder.size());
// Perform a depth-first ordering of the nodes in the CFG to give
// each node a unique identifier. This is accomplished by
// visiting the blocks in the CFG in post-order and numbering the
// Nodes in the block's expression Tree in depth-first order.
while (iter.hasPrevious()) {
Block block = (Block) iter.previous();
block.visit(new TreeVisitor() {
public void visitTree(Tree tree) {
tree.visitChildren(this);
}
public void visitNode(Node node) {
node.visitChildren(this);
node.setKey(count.value++);
}
});
}
// Build the (strongly connected) components and call
// visitor.visitComponent for each.
cfg.visit(new TreeVisitor() {
ArrayList stack = new ArrayList();
BitSet onStack = new BitSet(count.value + 1);
int[] low = new int[count.value + 1];
int[] dfs = new int[count.value + 1];
int dfsNumber = 1;
Node parent; // Parent in the SSA graph
// Visit the blocks in the CFG in reverse postorder
public void visitFlowGraph(FlowGraph cfg) {
ListIterator e = postOrder.listIterator(postOrder.size());
while (e.hasPrevious()) {
Block block = (Block) e.previous();
block.visit(this);
}
}
public void visitTree(Tree tree) {
parent = null;
tree.visitChildren(this);
}
// This method is essentially Figure 4.6 in Taylor Simpson's PhD
// Thesis: www.cs.rice.edu/~lts. The implementation is a little
// funky, though, because someone wanted to use visitors.
// Grumble.
public void visitNode(Node node) {
int dfn = dfs[node.key()];
// System.out.println("visit " + node + " key=" + node.key() +
// " dfn=" + dfn);
if (dfn == 0) {
// If this node isn't equivalent to the node the care
// about,
// fergit it!
if (!equivalent(node).contains(startNode))
return;
// The node in question has not yet been visited. Assign
// it
// the next dfNumber and add it to the stack. Mark all
// nodes that are equivalent to the node in question as
// being visited.
dfn = dfsNumber++;
low[dfn] = dfn;
stack.add(node);
onStack.set(dfn);
Iterator equiv = equivalent(node).iterator();
while (equiv.hasNext()) {
Node e = (Node) equiv.next();
dfs[e.key()] = dfn;
}
// Again examine each node, e, equivalent to the node in
// question. Then recursively visit the children of e in
// the SSA Graph.
Node grandParent = parent;
parent = node;
equiv = equivalent(node).iterator();
while (equiv.hasNext()) {
Node e = (Node) equiv.next();
Iterator children = children(e).iterator();
while (children.hasNext()) {
Node child = (Node) children.next();
child.visit(this);
}
}
parent = grandParent; // Restore true parent
// Now we finally get to the point where we can
// construct a
// strongly connected component. Pop all of the nodes
// off
// the stack until the node in question is reached.
if (low[dfn] == dfn) {
ArrayList scc = new ArrayList();
while (!stack.isEmpty()) {
Node v = (Node) stack.remove(stack.size() - 1);
onStack.clear(dfs[v.key()]);
scc.addAll(equivalent(v));
if (v == node) {
break;
}
}
// Sort the nodes in the SCC by their reverse
// post order numbers.
Collections.sort(scc, new Comparator() {
public int compare(Object a, Object b) {
int ka = ((Node) a).key();
int kb = ((Node) b).key();
return ka - kb;
}
});
if (DEBUG) {
System.out.print("SCC =");
Iterator e = scc.iterator();
while (e.hasNext()) {
Node v = (Node) e.next();
System.out.print(" " + v + "{" + v.key() + "}");
}
System.out.println();
}
// Visit the SCC with the visitor that was passed in.
visitor.visitComponent(scc);
}
if (parent != null) {
int parentDfn = dfs[parent.key()];
low[parentDfn] = Math.min(low[parentDfn], low[dfn]);
}
} else {
// We've already visited the node in question
if (parent != null) {
int parentDfn = dfs[parent.key()];
// (parent, node) is either a cross edge or a back edge.
if (dfn < parentDfn && onStack.get(dfn)) {
low[parentDfn] = Math.min(low[parentDfn], dfn);
}
}
}
}
});
}
/**
* Prints a textual representation of the strongly connected components of
* the SSAGraph to a PrintWriter.
*/
public void printSCCs(PrintWriter pw) {
Collection equivs = this.equivalences(); // A Collection of Sets
Iterator iter = equivs.iterator();
pw.println("Strongly Connected Components of the SSAGraph");
for (int i = 1; iter.hasNext(); i++) {
Set scc = (Set) iter.next();
Iterator sccIter = scc.iterator();
pw.println(" Component " + i);
while (sccIter.hasNext()) {
Node node = (Node) sccIter.next();
pw.println(" " + node + " [VN = " + node.valueNumber()
+ ", ID = " + System.identityHashCode(node) + "]");
}
}
}
}

@ -0,0 +1,12 @@
<html>
<body>
<p>Converts a control flow graph into static single assignment (SSA)
form. In SSA form, each variable in the method has a number
associated with it. Each target of an assignment statement is
assigned a new number. Subsequent uses of that variable are assigned
the same number. Thus, we have a compact form of definition-use
information. Many of the optimiations we do take advantage of SSA form.</p>
</body>
</html>

@ -0,0 +1,26 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
TBAA.class\
TypeInference.class
include ../class.mk

@ -0,0 +1,296 @@
/*
* Class: TBAA
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tbaa;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import edu.purdue.cs.bloat.editor.ClassHierarchy;
import edu.purdue.cs.bloat.editor.EditorContext;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.MemRefExpr;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.util.Assert;
import java.util.*;
/**
* Performs Type-Based Alias Analysis (TBAA) to determine if one expression can
* alias another. An expression may alias another expression if there is the
* possibility that they refer to the same location in memory. BLOAT models
* expressions that may reference memory locations with <tt>MemRefExpr</tt>s.
* There are two kinds of "access expressions" in Java: field accesses (<tt>FieldExpr</tt>
* and <tt>StaticFieldExpr</tt>) and array references (<tt>ArrayRefExpr</tt>).
* Access paths consist of one or more access expressions. For instance,
* <tt>a.b[i].c</tt> is an access expression.
*
* <p>
*
* TBAA uses the FieldTypeDecl relation to determine whether or not two access
* paths may refer to the same memory location.
*
* <p>
*
* <table>
* <th>
* <td>AP1 </td>
* <td>AP2 </td>
* <td>FieldTypeDecl(AP1, Ap2)</td>
* </th>
* <tr>
* <Td>p </td>
* <Td>p </td>
* <td>true </td>
* </tr>
* <tr>
* <td>p.f </td>
* <td>q.g </td>
* <td>(f = g) && FieldTypeDecl(p, q)</td>
* </tr>
* <tr>
* <td>p.f </td>
* <Td>q[i]</td>
* <td>false </td>
* </tr>
* <tr>
* <td>p[i]</td>
* <td>q[j]</td>
* <td>FieldTypeDecl(p, q) </td>
* </tr>
* <tr>
* <td>p </td>
* <td>q </td>
* <td>TypeDecl(p, q) </td>
* </tr>
* </table>
*
* <p>
*
* The TypeDecl(AP1, AP2) relation is defined as:
* <p align=center>
* Subtypes(Type(AP1)) INTERSECT Subtypes(Type(AP2)) != EMPTY
* </p>
*
* The subtype relationships are determined by the <tt>ClassHierarchy</tt>.
*
* @see ClassHierarchy
* @see MemRefExpr
* @see FieldExpr
* @see StaticFieldExpr
* @see ArrayRefExpr
*/
public class TBAA {
/**
* Returns true, if expression <tt>a</tt> can alias expression <tt>b</tt>.
*/
public static boolean canAlias(EditorContext context, Expr a, Expr b) {
// Only memory reference expressions can have aliases.
if (!(a instanceof MemRefExpr)) {
return false;
}
// Only memory reference expressions can have aliases.
if (!(b instanceof MemRefExpr)) {
return false;
}
// Equal expressions can be aliases.
if (a.equalsExpr(b)) {
return true;
}
MemberRef af = null; // Field accessed by expression a
MemberRef bf = null; // Field accessed by expression b
if (a instanceof FieldExpr) {
af = ((FieldExpr) a).field();
}
if (a instanceof StaticFieldExpr) {
af = ((StaticFieldExpr) a).field();
}
if (b instanceof FieldExpr) {
bf = ((FieldExpr) b).field();
}
if (b instanceof StaticFieldExpr) {
bf = ((StaticFieldExpr) b).field();
}
// Arrays and fields cannot alias the same location.
if (a instanceof ArrayRefExpr && bf != null) {
return false;
}
// Arrays and fields cannot alias the same location.
if (b instanceof ArrayRefExpr && af != null) {
return false;
}
Collection types = new LinkedHashSet();
types.add(a.type());
types.add(b.type());
ClassHierarchy hier = new ClassHierarchy(context, types, true);
// Only type-compatible arrays can alias the same location.
if (a instanceof ArrayRefExpr && b instanceof ArrayRefExpr) {
ArrayRefExpr aa = (ArrayRefExpr) a;
ArrayRefExpr bb = (ArrayRefExpr) b;
Type aaIndexType = aa.index().type();
Type bbIndexType = bb.index().type();
Type aaArrayType = aa.array().type();
Type bbArrayType = bb.array().type();
Assert.isTrue(Assert.isIntegral(aaIndexType), aa.index() + " in "
+ aa + " (" + aaIndexType + ") is not an integer");
Assert.isTrue(Assert.isIntegral(bbIndexType), bb.index() + " in "
+ bb + " (" + bbIndexType + ") is not an integer");
Assert.isTrue(aaArrayType instanceof ArrayType
|| aaArrayType.equals(Type.OBJECT)
|| aaArrayType.equals(new ObjectType(
"java.lang.Serializable"))
|| aaArrayType.equals(new ObjectType("jav.lang.Cloneable"))
|| aaArrayType.equals(Type.NULL), aa.array() + " in " + aa
+ " (" + aaArrayType + ") is not an array");
Assert.isTrue(bbArrayType instanceof ArrayType
|| bbArrayType.equals(Type.OBJECT)
|| bbArrayType.equals(new ObjectType(
"java.lang.Serializable"))
|| bbArrayType.equals(new ObjectType("jav.lang.Cloneable"))
|| bbArrayType.equals(Type.NULL), bb.array() + " in " + bb
+ " (" + bbArrayType + ") is not an array");
// Optimization: if constant indices. Only equal indices can
// alias the same location.
if (aa.index() instanceof ConstantExpr
&& bb.index() instanceof ConstantExpr) {
ConstantExpr ai = (ConstantExpr) aa.index();
ConstantExpr bi = (ConstantExpr) bb.index();
if (ai.value() != null && bi.value() != null) {
if (!ai.value().equals(bi.value())) {
return false;
}
}
}
return intersects(hier, aaArrayType, bbArrayType);
}
try {
if (af != null) {
ClassGen klass = context.editClass(((ObjectType) af
.declaringClass()).getClassName());
Field e = klass.containsField(af.name());
if (e == null) {
throw new NoSuchFieldException("Field: " + af.name()
+ "not found in class " + af.declaringClass());
}
if (e.isVolatile()) {
// context.release(e.fieldInfo());
return true;
}
if (e.isFinal()) {
// context.release(e.fieldInfo());
return false;
}
// context.release(e.fieldInfo());
// WE NEVER STARTED EDITING SO DON'T HAVE TO RELEASE IT
}
if (bf != null) {
ClassGen klass = context.editClass(((ObjectType) bf
.declaringClass()).getClassName());
Field e = klass.containsField(bf.name());
if (e == null) {
throw new NoSuchFieldException("Field: " + bf.name()
+ "not found in class " + bf.declaringClass());
}
if (e.isVolatile()) {
// context.release(e.fieldInfo());
return true;
}
if (e.isFinal()) {
// context.release(e.fieldInfo());
return false;
}
// context.release(e.fieldInfo());
// WE NEVER STARTED EDITING SO DON'T HAVE TO RELEASE IT
}
} catch (NoSuchFieldException e) {
// A field wasn't found. Silently assume there is an alias.
return true;
} catch (ClassNotFoundException cnfe) {
// A field wasn't found. Silently assume there is an alias.
return true;
}
// Only fields with the same name can alias the same location.
if (af != null && bf != null) {
return af.equals(bf);
}
// Default case. This shouldn't happen.
return intersects(hier, a.type(), b.type());
}
/**
* Returns <tt>true</tt> if type a and type c intersect. That is, the two
* types have a non-null intersection.
*/
private static boolean intersects(ClassHierarchy hier, Type a, Type b) {
return !hier.intersectType(a, b).equals(Type.NULL);
}
}

@ -0,0 +1,829 @@
/*
* Class: TypeInference
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tbaa;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.context.BloatContext;
import edu.purdue.cs.bloat.editor.ClassHierarchy;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.editor.MethodRef;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.ssa.ComponentVisitor;
import edu.purdue.cs.bloat.ssa.SSAGraph;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ArrayLengthExpr;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.CallMethodExpr;
import edu.purdue.cs.bloat.tree.CallStaticExpr;
import edu.purdue.cs.bloat.tree.CastExpr;
import edu.purdue.cs.bloat.tree.CatchExpr;
import edu.purdue.cs.bloat.tree.CheckExpr;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.InitStmt;
import edu.purdue.cs.bloat.tree.InstanceOfExpr;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.NegExpr;
import edu.purdue.cs.bloat.tree.NewArrayExpr;
import edu.purdue.cs.bloat.tree.NewExpr;
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.ReturnAddressExpr;
import edu.purdue.cs.bloat.tree.ShiftExpr;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.util.Assert;
import java.util.*;
/**
* Typed-based alias analysis requires that we know the types of all entities in
* a method. However, local variables and stack variables do not have declared
* types. Thus, we have to infer them.
*
* <p>
*
* <tt>TypeInference</tt> uses a simpilified version of everyone's favorite
* type inference algorithm from <u>Object-Oriented Type Systems</u> by
* Palsberg and Schwartzbach. It is simplified in that no interprocedural type
* information is calculated.
*
* <p>
*
* Here's how it works. Entities such as method arguments, fields, and constants
* have a known type. This known type is expressed in a constraint that
* constraints the entity to its type. Operations involving assignment (also
* phi-statements and stack operations) propagate these constraints to the
* targets of the assignments.
*/
public class TypeInference implements Optimization {
public static boolean DEBUG = false;
static final Type UNDEF = Type.getType("Lundef!;");
public void transform(MethodState state) {
transform(state.controlFlowGraph(), state.context());
}
/**
* Traverses the control flow graph and with the help of a number of vistors
* performs type-based alias analysis.
*
* @param cfg
* The control flow graph on which to perform TBAA.
* @param context
* Used to obtain a class heirarchy used for getting information
* about Types (classes).
*
* @see SSAGraph
* @see ComponentVisitor
* @see TreeVisitor
*
*/
public void transform(FlowGraph cfg, BloatContext context) {
ClassHierarchy hier = context.getHierarchy();
// First go through the CFG and determine the type of the local
// variables corresponding to method arguments. Assign those
// types to all uses of those local variables.
cfg.visit(new TreeVisitor() {
public void visitInitStmt(InitStmt stmt) {
// a := INIT
// [declared param type] <= [a]
MethodGen method = stmt.block().graph().method();
LocalExpr[] t = stmt.targets();
for (int i = 0; i < t.length; i++) {
LocalExpr var = t[i];
int index = var.index();
// If the method is static, there is no this pointer in
// the
// local variable table, so decrement index to point to
// the
// indexth local variable. This is needed with indexing
// into method.type().indexedParamTypes().
if (!method.isStatic()) {
index--;
}
Type type;
if (index == -1) {
// If the index is -1, then we're dealing with local
// variable 0 of a non-static method. This local
// variable
// is the this pointer. Its type is the type of the
// class
// in which the method is declared.
type = new ObjectType(method.getClassName());
} else {
// One of the method's arguments is being initialized.
// Figure out its type.
type = method.getArgumentType(index);
}
var.setType(type);
Iterator uses = var.uses().iterator();
// Set the type of the uses of the local variable, also.
while (uses.hasNext()) {
LocalExpr use = (LocalExpr) uses.next();
use.setType(type);
}
}
}
public void visitExpr(Expr expr) {
expr.visitChildren(this);
// We don't know the type of the expression yet.
expr.setType(UNDEF);
}
});
SSAGraph ssaGraph = new SSAGraph(cfg);
final TypeInferenceVisitor visitor = new TypeInferenceVisitor(hier,
ssaGraph);
// Visit each strong connected component in the SSAGraph and
// compute the type information using the TypeInferenceVisitor.
ssaGraph.visitComponents(new ComponentVisitor() {
public void visitComponent(List scc) {
visitor.changed = true;
while (visitor.changed) {
visitor.changed = false;
Iterator iter = scc.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
node.visit(visitor);
}
}
}
});
// Convert POS_SHORT types back into SHORT types and POS_BYTE
// types back into BYTE types.
cfg.visit(new TreeVisitor() {
public void visitExpr(Expr expr) {
expr.visitChildren(this);
if (expr.type().equals(ClassHierarchy.POS_SHORT)) {
expr.setType(Type.SHORT);
} else if (expr.type().equals(ClassHierarchy.POS_BYTE)) {
expr.setType(Type.BYTE);
}
}
});
if (DEBUG) {
// Print out all the type information and do some checking.
cfg.visit(new TreeVisitor() {
public void visitExpr(Expr expr) {
expr.visitChildren(this);
System.out.println("typeof(" + expr + ") = " + expr.type());
if (expr.type().equals(UNDEF)) {
System.out.println("WARNING: typeof(" + expr
+ ") = UNDEF");
}
Assert
.isFalse(expr.type().equals(
ClassHierarchy.POS_SHORT));
Assert.isFalse(expr.type().equals(ClassHierarchy.POS_BYTE));
}
});
}
}
public String preDebugMessage() {
return "---------Doing type inference--------";
}
public String traceMessage(String dateString) {
return " Type Inferencing: " + dateString;
}
public String postDebugMessage() {
return null;
}
}
/**
* Does most of the type inference work. It generates the type constraints for
* the expressions in the CFG.
*/
class TypeInferenceVisitor extends TreeVisitor {
public boolean changed;
public ClassHierarchy hier;
SSAGraph ssaGraph;
public TypeInferenceVisitor(ClassHierarchy hier, SSAGraph ssaGraph) {
this.hier = hier;
this.ssaGraph = ssaGraph;
}
public void visitExpr(Expr expr) {
throw new RuntimeException(expr + " not supported");
}
// Make a new start constraint for the expression being shifted.
public void visitShiftExpr(ShiftExpr expr) {
if (Assert.isIntegral(expr.expr().type())
|| expr.expr().type().equals(ClassHierarchy.POS_SHORT)
|| expr.expr().type().equals(ClassHierarchy.POS_BYTE)) {
start(expr, Type.INT);
} else {
prop(expr, expr.expr());
}
}
// If either of the ArithExpr's operands has type INTEGER, then the
// entire expression must have type INTEGER. Otherwise, the type of
// one of the operands must be undefined, or both operands have the
// same type. If the ArithExpr is one of the compare operations,
// then it has an INTEGER type.
public void visitArithExpr(ArithExpr expr) {
if (Assert.isIntegral(expr.left().type())
|| expr.left().type().equals(ClassHierarchy.POS_SHORT)
|| expr.left().type().equals(ClassHierarchy.POS_BYTE)) {
start(expr, Type.INT);
} else if (Assert.isIntegral(expr.right().type())
|| expr.right().type().equals(ClassHierarchy.POS_SHORT)
|| expr.right().type().equals(ClassHierarchy.POS_BYTE)) {
start(expr, Type.INT);
} else {
Assert.isTrue(expr.left().type().equals(TypeInference.UNDEF)
|| expr.right().type().equals(TypeInference.UNDEF)
|| expr.left().type().equals(expr.right().type()), expr
.left()
+ ".type() = "
+ expr.left().type()
+ " != "
+ expr.right()
+ ".type() = " + expr.right().type());
if (expr.operation() == ArithExpr.CMP
|| expr.operation() == ArithExpr.CMPL
|| expr.operation() == ArithExpr.CMPG) {
start(expr, Type.INT);
} else {
prop(expr, expr.left());
}
}
}
// If the expression being negated has an integral type, then the
// type of the expression in an INTEGER.
public void visitNegExpr(NegExpr expr) {
if (Assert.isIntegral(expr.expr().type())
|| expr.expr().type().equals(ClassHierarchy.POS_SHORT)
|| expr.expr().type().equals(ClassHierarchy.POS_BYTE)) {
start(expr, Type.INT);
} else {
prop(expr, expr.expr());
}
}
public void visitReturnAddressExpr(ReturnAddressExpr expr) {
start(expr, ReturnaddressType.NO_TARGET);
}
public void visitCheckExpr(CheckExpr expr) {
prop(expr, expr.expr());
}
// Why does it start the expression with an INTEGER type???
// Ans: Because instanceof returns a boolean, which is dealt with as an
// int.
public void visitInstanceOfExpr(InstanceOfExpr expr) {
start(expr, Type.INT);
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
start(expr, Type.INT);
}
// If a VarExpr does not define a variable, then propagate the type
// of the expression that does define the variable to the VarExpr.
public void visitVarExpr(VarExpr expr) {
if (!expr.isDef()) {
if (expr.def() != null) {
prop(expr, expr.def());
}
}
}
// Not surprisingly, StackManipStmts are ugly looking. The type
// information is propagated from the "before" stack variable to the
// appropriate "after" stack variable. As seen in other places, the
// transformation is given by an integer array.
public void visitStackManipStmt(StackManipStmt stmt) {
// a := b
// [b] <= [a]
StackExpr[] target = stmt.target();
StackExpr[] source = stmt.source();
switch (stmt.kind()) {
case StackManipStmt.SWAP:
// 0 1 -> 1 0
Assert.isTrue(source.length == 2 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0 });
break;
case StackManipStmt.DUP:
// 0 -> 0 0
Assert.isTrue(source.length == 1 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 0, 0 });
break;
case StackManipStmt.DUP_X1:
// 0 1 -> 1 0 1
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
break;
case StackManipStmt.DUP_X2:
if (source.length == 3) {
// 0 1 2 -> 2 0 1 2
Assert.isTrue(source.length == 3 && target.length == 4,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 2, 0, 1, 2 });
} else {
// 0-1 2 -> 2 0-1 2
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
case StackManipStmt.DUP2:
if (source.length == 2) {
// 0 1 -> 0 1 0 1
Assert.isTrue(target.length == 4, "Illegal statement: " + stmt);
manip(source, target, new int[] { 0, 1, 0, 1 });
} else {
// 0-1 -> 0-1 0-1
Assert.isTrue(source.length == 1 && target.length == 2,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 0, 0 });
}
break;
case StackManipStmt.DUP2_X1:
if (source.length == 3) {
// 0 1 2 -> 1 2 0 1 2
Assert.isTrue(target.length == 5, "Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 2, 0, 1, 2 });
} else {
// 0 1-2 -> 1-2 0 1-2
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
case StackManipStmt.DUP2_X2:
if (source.length == 4) {
// 0 1 2 3 -> 2 3 0 1 2 3
Assert.isTrue(target.length == 6, "Illegal statement: " + stmt);
manip(source, target, new int[] { 2, 3, 0, 1, 2, 3 });
} else if (source.length == 3) {
if (target.length == 5) {
// 0-1 2 3 -> 2 3 0-1 2 3
manip(source, target, new int[] { 1, 2, 0, 1, 2 });
} else {
// 0 1 2-3 -> 2-3 0 1 2-3
Assert.isTrue(target.length == 4, "Illegal statement: "
+ stmt);
manip(source, target, new int[] { 2, 0, 1, 2 });
}
} else {
// 0-1 2-3 -> 2-3 0-1 2-3
Assert.isTrue(source.length == 2 && target.length == 3,
"Illegal statement: " + stmt);
manip(source, target, new int[] { 1, 0, 1 });
}
break;
}
stmt.visitChildren(this);
}
private void manip(StackExpr[] source, StackExpr[] target, int[] s) {
for (int i = 0; i < s.length; i++) {
prop(target[i], source[s[i]]);
}
}
// The type of the expression being stored flows into the target of
// the store. The type of the target flows into the StoreExpr.
public void visitStoreExpr(StoreExpr expr) {
// a := b
// [b] <= [a]
prop(expr.target(), expr.expr());
prop(expr, expr.target());
}
// The type of the exception being caught flows into the type of the
// CatchExpr.
public void visitCatchExpr(CatchExpr expr) {
// Catch(t)
// t <= [Catch(t)]
Type catchType = expr.catchType();
if (catchType == Type.NULL) {
catchType = Type.THROWABLE;
}
start(expr, catchType);
}
// The type information of each of the PhiStmt's operands flows into
// the target. If an operand is undefined, the type of the target
// flows into that operand so that it will have a type.
public void visitPhiStmt(PhiStmt stmt) {
// a := Phi(b, c)
// [b] <= [a]
// [c] <= [a]
List back = new ArrayList(stmt.operands().size());
Iterator e = stmt.operands().iterator();
while (e.hasNext()) {
Expr expr = (Expr) e.next();
if (expr instanceof VarExpr && expr.def() == null) {
back.add(expr);
} else {
prop(stmt.target(), expr);
}
}
// Propagate the type back to the operands which are undefined.
// Otherwise, they won't be able to get a type.
e = back.iterator();
while (e.hasNext()) {
Expr expr = (Expr) e.next();
if (expr.def() == null) {
prop(expr, stmt.target());
}
}
}
// If the ArrayRefExpr is not a definition, then the type of the
// elements in the array flows into the type of the ArrayRefExpr.
// This is all contingent upon the type of the array elements being
// defined, non-object, not serializable, not clonable, and not
// null.
public void visitArrayRefExpr(ArrayRefExpr expr) {
// a[i]
// [a[i]] <= [element type of a]
Expr array = expr.array();
if (!expr.isDef()) {
if (!array.type().equals(TypeInference.UNDEF)
&& !array.type().equals(Type.OBJECT)
&& !array.type().equals(
new ObjectType("java.lang.Serializable"))
&& !array.type().equals(
new ObjectType("java.lang.Cloneable"))
&& !array.type().equals(Type.NULL)) {
Assert.isTrue(array.type() instanceof ArrayType, array + " in "
+ expr + " (" + array.type() + ") is not an array");
start(expr, ((ArrayType) expr.array().type()).getElementType());
}
}
}
// The return type of the method flow into the CallMethodExpr.
public void visitCallMethodExpr(CallMethodExpr expr) {
// x.m(a), m in class C
// [x] <= C
// [a] <= [declared param type]
// [declared return type] <= [x.m(a)]
MethodRef method = expr.method();
Type returnType = method.returnType();
start(expr, returnType);
}
// The return type of the method flows into the CallStaticExpr.
public void visitCallStaticExpr(CallStaticExpr expr) {
// m(a)
// [a] <= [declared param type]
// [declared return type] <= [m(a)]
MethodRef method = expr.method();
Type returnType = method.returnType();
start(expr, returnType);
}
// The type to which an expression is cast flows into the CastExpr.
public void visitCastExpr(CastExpr expr) {
// (C) a
// [(C) a] <= C
start(expr, expr.castType());
}
// The type of the constant flows into the type of the ConstantExpr.
public void visitConstantExpr(ConstantExpr expr) {
// "a"
// String <= ["a"]
Object value = expr.value();
if (value == null) {
start(expr, Type.NULL);
return;
}
if (value instanceof String) {
start(expr, Type.STRING);
return;
}
if (value instanceof Boolean) {
start(expr, Type.BOOLEAN);
return;
}
if (value instanceof Integer) {
start(expr, Type.INT);
return;
}
if (value instanceof Long) {
start(expr, Type.LONG);
return;
}
if (value instanceof Float) {
start(expr, Type.FLOAT);
return;
}
if (value instanceof Double) {
start(expr, Type.DOUBLE);
return;
}
int v;
if (value instanceof Byte) {
v = ((Byte) value).byteValue();
} else if (value instanceof Short) {
v = ((Short) value).shortValue();
} else if (value instanceof Character) {
v = ((Character) value).charValue();
} else {
throw new RuntimeException();
}
if (v >= 0) {
if (v <= 1) {
start(expr, Type.BOOLEAN); // It'll fit in a BOOLEAN
} else if (v <= Byte.MAX_VALUE) {
start(expr, ClassHierarchy.POS_BYTE);
} else if (v <= Short.MAX_VALUE) {
start(expr, ClassHierarchy.POS_SHORT);
} else if (v <= Character.MAX_VALUE) {
start(expr, Type.CHAR);
} else {
start(expr, Type.INT);
}
} else {
// The constant's value is negative
if (Byte.MIN_VALUE <= v) {
start(expr, Type.BYTE); // It'll fit in a BYTE
} else if (Short.MIN_VALUE <= v) {
start(expr, Type.SHORT);
} else {
start(expr, Type.INT);
}
}
}
// If the FieldExpr is a definition, the type of the field flows
// into the type of the FieldExpr.
public void visitFieldExpr(FieldExpr expr) {
// a.f, f in class C
// [a] <= C
// [declared field type] <= [a.f]
MemberRef field = expr.field();
// if (! expr.isDef()) {
start(expr, field.type());
// }
}
// If the expression representing the type of the array being
// created is defined, then and array of that type flows into the
// type of the NewArrayExpr.
public void visitNewArrayExpr(NewArrayExpr expr) {
// new t[i]
// array-1-of-t <= [new t[i]]
if (!expr.elementType().equals(TypeInference.UNDEF)) {
start(expr, new ArrayType(expr.elementType(), 1));
}
}
// The type of the object being created flows into the NewExpr.
public void visitNewExpr(NewExpr expr) {
// new C
// C <= [new C]
start(expr, expr.objectType());
}
// If the type of the expression specifying the type of the array
// being created is defined, then that type flows into the type of
// the NewMultiArrayExpr.
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
// new t[i][j][k]
// array-dim-of-t <= [new t[i][j][k]]
if (!expr.elementType().equals(TypeInference.UNDEF)) {
start(expr, new ArrayType(expr.elementType(),
expr.dimensions().length));
}
}
// If the field reference is a definition, then the type of the
// field flows into the type of the StaticFieldExpr.
public void visitStaticFieldExpr(StaticFieldExpr expr) {
// C.f
// [declared field type] <= [C.f]
MemberRef field = expr.field();
if (!expr.isDef()) {
start(expr, field.type());
}
}
// Initializes the constraint propagation by assigning a type to a
// given expression.
private void start(Expr expr, Type type) {
if (TypeInference.DEBUG) {
System.out.println("start " + expr + " <- " + type);
}
if (type.equals(TypeInference.UNDEF)) {
return;
}
if (!expr.type().equals(TypeInference.UNDEF)) {
if (TypeInference.DEBUG) {
System.out.print("union of " + expr.type() + " and " + type);
}
if (!Assert.isIntegral(type)
&& !type.equals(ClassHierarchy.POS_BYTE)
&& !type.equals(ClassHierarchy.POS_SHORT)) {
Assert.isTrue(Assert.simple(type).equals(
Assert.simple(expr.type())));
if (type instanceof ReferenceType) {
// The expr and type may have different types. So, deal
// with the common supertype of both type and
// expr.type().
// That is, the type to which both belong.
type = hier.unionType(type, expr.type());
}
} else {
// We're dealing with one of the integral types. Take the
// union of the two types and work with that.
BitSet v1 = ClassHierarchy.typeToSet(type);
BitSet v2 = ClassHierarchy.typeToSet(expr.type());
v1.or(v2);
type = ClassHierarchy.setToType(v1);
}
if (TypeInference.DEBUG) {
System.out.println(" is " + type);
}
}
// Set the type of all nodes equivalent to expr to the type we're
// working with.
Iterator iter = ssaGraph.equivalent(expr).iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
if (node instanceof Expr) {
Expr e = (Expr) node;
if (e.setType(type)) {
changed = true;
}
}
}
}
// Propagates the type of the source expression to all expressions
// equivalent to the other expr.
private void prop(Expr expr, Expr source) {
if (TypeInference.DEBUG) {
System.out.println("prop " + expr + " <- " + source);
}
start(expr, source.type());
}
}

@ -0,0 +1,12 @@
<html>
<body>
<p>Performs type-base alias analysis (TBAA) on a control flow graph.
Type-based alias analysis considers the types of variables when
deciding whether or not two variable can refer to the same object.
Before TBAA can occur, the types of variables are inferred. Type
inference requires information about the class hierarchy of classes
being BLOATed.</p>
</body>
</html>

@ -0,0 +1,19 @@
package edu.purdue.cs.bloat.tests;
public class BloatTester1 {
int testDepth(int a) throws Exception {
while (String.class != null)
if (this.getClass().getMethods()[0].hashCode() == a)
do {
try {
this.getClass().getMethod("testDepth",
new Class[] { Integer.TYPE }).invoke(this,
new Object[] { new Integer(2) });
} catch (ArrayIndexOutOfBoundsException e) {
throw new ClassNotFoundException("foo", e);
}
} while (0 == 5);
return 0;
}
}

@ -0,0 +1,23 @@
package edu.purdue.cs.bloat.tests;
public class BloatTester2 {
public static BloatTester2 frob() throws Exception {
try {
System.in.close();
System.out.println((new Object() {
public String snap() {
try {
return "" + "snap";
} catch (NullPointerException e) {
throw new IllegalArgumentException(e.toString());
}
}
}).snap());
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
}
return null;
}
}

@ -0,0 +1,25 @@
package edu.purdue.cs.bloat.tests;
public class BloatTester3 {
void frob() {
try {
int x = 5;
int y = 50 * x;
if (x > 9)
throw new ClassNotFoundException();
if (y < 99) {
try {
String in = "elvis";
in.toLowerCase();
} catch (Exception e) {
;
}
}
} catch (ClassNotFoundException e) {
;
}
}
}

@ -0,0 +1,28 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
BloatTester1.class \
BloatTester2.class \
BloatTester3.class
include ../class.mk

@ -0,0 +1,712 @@
/*
* Class: DeadCodeElimintation
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.tree.AddressStoreStmt;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ArrayLengthExpr;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.CallMethodExpr;
import edu.purdue.cs.bloat.tree.CallStaticExpr;
import edu.purdue.cs.bloat.tree.CastExpr;
import edu.purdue.cs.bloat.tree.CatchExpr;
import edu.purdue.cs.bloat.tree.DefExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.ExprStmt;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.GotoStmt;
import edu.purdue.cs.bloat.tree.IfStmt;
import edu.purdue.cs.bloat.tree.InitStmt;
import edu.purdue.cs.bloat.tree.JsrStmt;
import edu.purdue.cs.bloat.tree.JumpStmt;
import edu.purdue.cs.bloat.tree.LabelStmt;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MonitorStmt;
import edu.purdue.cs.bloat.tree.NewArrayExpr;
import edu.purdue.cs.bloat.tree.NewExpr;
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.RCExpr;
import edu.purdue.cs.bloat.tree.RetStmt;
import edu.purdue.cs.bloat.tree.ReturnExprStmt;
import edu.purdue.cs.bloat.tree.ReturnStmt;
import edu.purdue.cs.bloat.tree.SCStmt;
import edu.purdue.cs.bloat.tree.SRStmt;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.SwitchStmt;
import edu.purdue.cs.bloat.tree.ThrowStmt;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.UCExpr;
import edu.purdue.cs.bloat.tree.VarExpr;
import edu.purdue.cs.bloat.tree.ZeroCheckExpr;
import edu.purdue.cs.bloat.util.Assert;
import java.util.*;
/**
* DeadCodeElimination performs SSA-based dead code elimination as described in
* [Cytron, et. al. 91]. The idea behind dead code elimination is that there are
* some instructions that do not contribute anything useful to the result of the
* program. Most dead code is introduced by other optimizations.
*
* A program statement is live if one or more of the following holds:
*
* <ol>
*
* <li>The statement effects program output. In Java this is a lot more than
* just I/O. We must be conservative and assume that exceptions and monitor
* expression are always live.
*
* <li>The statement is an assignment statement whose target is used in a live
* statement.
*
* <li>The statement is a conditional branch and there are live statements
* whose execution depend on the conditional branch.
*
* <ol>
*
* Basically, the algorithm proceeds by marking a number of statements as being
* pre-live and then uses a worklist to determine which statements must also be
* live by the above three conditions.
*/
public class DeadCodeElimination implements Optimization {
public static boolean DEBUG = false;
private static final int DEAD = 0;
private static final int LIVE = 1;
// Keep a work list of expressions that need to be made live.
LinkedList worklist;
public void transform(MethodState state) {
transform(state.controlFlowGraph());
}
/**
* Performs dead code elimination.
*/
private void transform(FlowGraph cfg) {
// Mark all nodes in the tree as DEAD.
cfg.visit(new TreeVisitor() {
public void visitNode(Node node) {
node.visitChildren(this);
node.setKey(DEAD);
}
});
worklist = new LinkedList();
// Visit the nodes in the tree and mark nodes that we know must be
// LIVE.
cfg.visit(new TreeVisitor() {
public void visitMonitorStmt(MonitorStmt stmt) {
// NullPointerException, IllegalMonitorStateException
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitInitStmt(InitStmt stmt) {
// Needed to correctly initialize the formal parameters when
// coloring
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitJsrStmt(JsrStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitAddressStoreStmt(AddressStoreStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitRetStmt(RetStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitSRStmt(SRStmt stmt) {
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitSCStmt(SCStmt stmt) {
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitNewArrayExpr(NewArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitNewExpr(NewExpr expr) {
// Memory allocation
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitStackExpr(StackExpr expr) {
if (expr.stmt() instanceof PhiStmt) {
return;
}
// Stack change
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
// NullPointerException or DivideByZeroException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitRCExpr(RCExpr expr) {
// Residency check
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitUCExpr(UCExpr expr) {
// Update check
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitCastExpr(CastExpr expr) {
// ClassCastException
if (expr.castType() instanceof ReferenceType) {
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
} else {
expr.visitChildren(this);
}
}
public void visitArithExpr(ArithExpr expr) {
// DivideByZeroException
if (expr.operation() == ArithExpr.DIV
|| expr.operation() == ArithExpr.REM) {
if (Assert.isIntegral(expr.type())) {
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
return;
}
}
expr.visitChildren(this);
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
// NullPointerException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
// NullPointerException, ArrayIndexOutOfBoundsException,
// ArrayStoreException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitFieldExpr(FieldExpr expr) {
// NullPointerException
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitCallStaticExpr(CallStaticExpr expr) {
// Call
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Call
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitCatchExpr(CatchExpr expr) {
// Stack change
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
}
public void visitStackManipStmt(StackManipStmt stmt) {
// Stack change
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitThrowStmt(ThrowStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitSwitchStmt(SwitchStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitIfStmt(IfStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitGotoStmt(GotoStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitReturnStmt(ReturnStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitReturnExprStmt(ReturnExprStmt stmt) {
// Branch
if (DEBUG) {
System.out.println(stmt + " is prelive");
}
makeLive(stmt);
}
public void visitStoreExpr(StoreExpr expr) {
// Can change a variable visible outside the method.
if (!(expr.target() instanceof LocalExpr)) {
if (DEBUG) {
System.out.println(expr + " is prelive");
}
makeLive(expr);
} else {
expr.visitChildren(this);
}
}
});
// Go through the nodes in the worklist and make the nodes that
// defined the VarExprs live.
while (!worklist.isEmpty()) {
VarExpr expr = (VarExpr) worklist.removeFirst();
DefExpr def = expr.def();
if (def != null) {
if (DEBUG) {
System.out.println("making live def of " + expr);
System.out.println(" def = " + def);
}
makeLive(def.parent());
}
}
// Remove dead stores.
cfg.visit(new TreeVisitor() {
public void visitStoreExpr(StoreExpr expr) {
Expr lhs = expr.target();
Expr rhs = expr.expr();
if (lhs.key() == DEAD && rhs.key() == LIVE) {
rhs.setParent(null);
expr.replaceWith(rhs, false);
lhs.cleanup();
expr.cleanupOnly();
lhs.setKey(DEAD);
expr.setKey(DEAD);
rhs.visit(this);
} else {
expr.visitChildren(this);
}
}
});
// Pull out live expressions from their dead parents. Gee, Nate,
// what a lovely sentiment. I'll think I'll send that one to
// Hallmark.
cfg.visit(new TreeVisitor() {
public void visitStmt(Stmt stmt) {
if (stmt.key() == DEAD) {
stmt.visitChildren(this);
}
}
public void visitExpr(Expr expr) {
if (expr.key() == DEAD) {
expr.visitChildren(this);
return;
}
Node parent = expr.parent();
if (parent.key() == LIVE) {
// expr will removed later
return;
}
if (parent instanceof ExprStmt) {
// The expr and its parent are both dead, but expr
// resides
// in an ExprStmt. We want the parent after all.
parent.setKey(LIVE);
return;
}
// We are going to remove the expr's parent, but keep the
// expr. Add eval(expr) [ExprStmt] before the stmt containing
// the expr. This is safe, since any exprs to the left in the
// statement's tree which are live have already been
// extracted.
Stmt oldStmt = expr.stmt();
Tree tree = parent.block().tree();
// Replace the expr with an unused stack expr.
StackExpr t = tree.newStack(expr.type());
expr.replaceWith(t, false);
t.setValueNumber(expr.valueNumber());
ExprStmt stmt = new ExprStmt(expr);
stmt.setValueNumber(expr.valueNumber());
stmt.setKey(LIVE);
tree.addStmtBefore(stmt, oldStmt);
// The old statement is dead and will be removed later.
Assert.isTrue(oldStmt.key() == DEAD, oldStmt
+ " should be dead");
}
});
// Finally, remove the dead statements from the Tree.
cfg.visit(new TreeVisitor() {
public void visitTree(Tree tree) {
Iterator e = tree.stmts().iterator();
while (e.hasNext()) {
Stmt stmt = (Stmt) e.next();
if (stmt.key() == DEAD) {
if (stmt instanceof LabelStmt) {
continue;
}
if (stmt instanceof JumpStmt) {
continue;
}
if (DEBUG) {
System.out.println("Removing DEAD " + stmt);
}
e.remove();
}
}
}
});
worklist = null;
}
// /**
// * Make all of a statement's children LIVE. I don't think its used.
// *
// * @param stmt
// * A statement whose children to make live.
// */
// void reviveStmt(Stmt stmt) {
// stmt.visit(new TreeVisitor() {
// public void visitExpr(Expr expr) {
// expr.setKey(LIVE);
// expr.visitChildren(this);
// }
// });
// }
/**
* Make a node and all of its children (recursively) LIVE.
*
* @param node
* A node to make LIVE.
*/
void makeLive(Node node) {
if (node instanceof StoreExpr) {
// Make the StoreExpr, its target, and its RHS live. Add the
// target and the RHS to the worklist.
StoreExpr expr = (StoreExpr) node;
if (expr.key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + expr + " in "
+ expr.parent());
}
expr.setKey(LIVE);
}
if (expr.target().key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + expr.target() + " in "
+ expr);
}
expr.target().setKey(LIVE);
if (expr.target() instanceof VarExpr) {
worklist.add(expr.target());
}
}
if (expr.expr().key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + expr.expr() + " in "
+ expr);
}
expr.expr().setKey(LIVE);
if (expr.expr() instanceof VarExpr) {
worklist.add(expr.expr());
}
}
}
if (node instanceof Expr) {
// If one expression inside an ExprStmt is live, then the entire
// ExprStmt is live.
Node parent = ((Expr) node).parent();
if (parent instanceof ExprStmt) {
node = parent;
}
}
node.visit(new TreeVisitor() {
public void visitStoreExpr(StoreExpr expr) {
// Don't make local variable targets live yet. If the
// variable is used in a live expression, the target will be
// made live later.
if (expr.target() instanceof LocalExpr) {
expr.expr().visit(this);
} else {
visitExpr(expr);
}
}
public void visitVarExpr(VarExpr expr) {
if (expr.key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + expr + " in "
+ expr.parent());
}
expr.setKey(LIVE);
worklist.add(expr);
}
}
public void visitExpr(Expr expr) {
if (expr.key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + expr + " in "
+ expr.parent());
}
expr.setKey(LIVE);
}
expr.visitChildren(this);
}
public void visitStmt(Stmt stmt) {
if (stmt.key() == DEAD) {
if (DEBUG) {
System.out.println("making live " + stmt);
}
stmt.setKey(LIVE);
}
stmt.visitChildren(this);
}
});
}
public String traceMessage(String dateString) {
return " Dead Code Elimination: " + dateString;
}
public String preDebugMessage() {
return "---Before Dead Code Elimination--";
}
public String postDebugMessage() {
return "---After Dead Code Elimination---";
}
}

@ -0,0 +1,301 @@
/*
* Class: ExprPropagation
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import java.util.Iterator;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.LeafExpr;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MemExpr;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.ReplaceVisitor;
import edu.purdue.cs.bloat.tree.Stmt;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
/**
* Performs copy and constant propagation on the blocks in a control flow graph.
*/
public class ExprPropagation implements Optimization {
public static boolean DEBUG = false;
FlowGraph cfg;
boolean changed; // Did the cfg change?
public void transform(MethodState state) {
transform(state.controlFlowGraph());
}
/**
* Performs the propagation.
*/
private void transform(FlowGraph cfg) {
this.cfg = cfg;
changed = true;
while (changed) {
changed = false;
propagate();
}
}
/**
* Propagate expressions through the control flow graph in hopes of reducing
* the number of local variables.
*/
private void propagate() {
cfg.visit(new TreeVisitor() {
Iterator iter;
public void visitTree(Tree tree) {
iter = tree.stmts().iterator();
while (iter.hasNext()) {
Stmt stmt = (Stmt) iter.next();
stmt.visit(this);
}
}
public void visitStoreExpr(StoreExpr expr) {
expr.visitChildren(this);
if (!(expr.target() instanceof LocalExpr)) {
// If we're not assigning to a local variable, fergit it
return;
}
LocalExpr lhs = (LocalExpr) expr.target();
Expr rhs = expr.expr();
// L := (M := E)
// use L
// use M
//
// -->
//
// L := E
// use L
// use L
//
// Since we've already visited (M := E), M could not be
// eliminated. So, after propagating M to L, we won't be
// able to eliminate L either, so don't even try.
//
if (rhs instanceof StoreExpr) {
StoreExpr store = (StoreExpr) rhs;
MemExpr rhsLHS = store.target();
Expr rhsRHS = store.expr();
if (rhsLHS instanceof LocalExpr) {
// Replace uses of M with L.
// We need to make a copy of the lhs since it is a
// def an consequently does not contain a pointer to
// a def.
LocalExpr copy = (LocalExpr) lhs.clone();
copy.setDef(lhs);
if (propExpr(expr.block(), (LocalExpr) rhsLHS, copy)) {
// If all uses of the rhsRHS local variable were
// replaced, replace all occurrences of the rhs
// with the
// local variable of rhsRHS.
changed = true;
expr.visit(new ReplaceVisitor(rhs, rhsRHS));
rhsLHS.cleanup();
rhs.cleanupOnly();
}
// Be sure to cleanup the copy.
copy.cleanup();
}
}
// This next part is awful and comented out. Propagating
// local variables like this fails to take into account
// the live ranges. When we have L := M, it replaces L with
// M after M has been overwritten. Arg.
/*
* else if (rhs instanceof LeafExpr) { if
* (propExpr(expr.block(), lhs, rhs)) { // If all uses of the
* local variable in the lhs were // replaced with the LeafExpr
* in the rhs, then the store // (L := X) is useless. Replace it
* with (eval X) so it // can be removed later. changed = true; //
* Replace eval (L := X) with eval X // Dead code elimination
* will remove it. if (expr.parent() instanceof ExprStmt)
* iter.remove(); else expr.replaceWith((Expr) rhs.clone()); } }
*/
}
public void visitPhiStmt(PhiStmt stmt) {
Expr lhs = stmt.target();
if (!(lhs instanceof LocalExpr)) {
// If we're not assigning into a local variable, fergit
// it
return;
}
// Look at all of the operands of the PhiStmt. If all of the
// operands are either the same local variable or the same
// constant, then propagate an operand (doesn't matter which
// one because they're all the same value) to all uses of the
// target of the PhiStmt.
Iterator e = stmt.operands().iterator();
if (!e.hasNext()) {
return;
}
Expr rhs = (Expr) e.next();
if (!(rhs instanceof LeafExpr)) {
return;
}
while (e.hasNext()) {
Expr operand = (Expr) e.next();
if (rhs instanceof LocalExpr) {
if (operand instanceof LocalExpr) {
if (rhs.def() != operand.def()) {
return;
}
} else {
return;
}
} else if (rhs instanceof ConstantExpr) {
if (!rhs.equalsExpr(operand)) {
return;
}
} else {
return;
}
}
if (propExpr(stmt.block(), (LocalExpr) lhs, rhs)) {
// If all uses of the PhiStmt's target were replaced,
// remove
// it from the expression tree.
changed = true;
iter.remove();
}
}
});
}
/**
* Propagates the expression in rhs to all uses of the lhs. Returns true, if
* all of the uses of the lhs were replaced.
*/
boolean propExpr(Block block, LocalExpr lhs, Expr rhs) {
if (DEBUG) {
System.out.println("prop " + rhs + " to uses of " + lhs);
System.out.println(" uses of lhs = " + lhs.uses());
}
if (rhs instanceof LocalExpr) {
// We can't prop a local to a PhiStmt operand, so don't bother
// doing the propagation at all.
Iterator e = lhs.uses().iterator();
while (e.hasNext()) {
LocalExpr use = (LocalExpr) e.next();
if (use.parent() instanceof PhiStmt) {
return false;
}
}
// Replaces all uses of the lhs with the rhs. Both are local
// variables.
e = lhs.uses().iterator();
while (e.hasNext()) {
LocalExpr use = (LocalExpr) e.next();
use.replaceWith((Expr) rhs.clone());
}
return true;
} else {
boolean replacedAll = true;
Iterator e = lhs.uses().iterator();
while (e.hasNext()) {
LocalExpr use = (LocalExpr) e.next();
if (use.parent() instanceof PhiCatchStmt) {
replacedAll = false;
} else {
use.replaceWith((Expr) rhs.clone());
}
}
return replacedAll;
}
}
public String traceMessage(String dateString) {
return " Copy propagation: " + dateString;
}
public String preDebugMessage() {
return "-----Before Copy Propagation-----";
}
public String postDebugMessage() {
return "------After Copy Propagation-----";
}
}

@ -0,0 +1,36 @@
# All files in the distribution of BLOAT (Bytecode Level Optimization and
# Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
# Research Foundation of Purdue University. All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies, and that any documentation, announcements, and other
# materials related to such distribution and use acknowledge that the
# software was developed at Purdue University, West Lafayette, IN by
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
# may be made for copies, derivations, or distributions of this
# material without the express written consent of the copyright
# holder. Neither the name of the University nor the name of the
# author may be used to endorse or promote products derived from this
# material without specific prior written permission. THIS SOFTWARE
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# Java is a trademark of Sun Microsystems, Inc.
CLASS = \
CompactArrayInitializer.class\
DeadCodeElimination.class\
ExprPropagation.class\
NodeComparator.class\
Peephole.class\
SSAPRE.class\
SideEffectChecker.class\
StackPRE.class\
ValueFolder.class\
ValueFolding.class\
ValueNumbering.class
#PersistentCheckElimination.class\
include ../class.mk

@ -0,0 +1,594 @@
/*
* Class: NodeComparator
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import edu.purdue.cs.bloat.tree.AddressStoreStmt;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ArrayLengthExpr;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.CallMethodExpr;
import edu.purdue.cs.bloat.tree.CallStaticExpr;
import edu.purdue.cs.bloat.tree.CastExpr;
import edu.purdue.cs.bloat.tree.CatchExpr;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.ExprStmt;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.GotoStmt;
import edu.purdue.cs.bloat.tree.IfCmpStmt;
import edu.purdue.cs.bloat.tree.IfZeroStmt;
import edu.purdue.cs.bloat.tree.InitStmt;
import edu.purdue.cs.bloat.tree.InstanceOfExpr;
import edu.purdue.cs.bloat.tree.JsrStmt;
import edu.purdue.cs.bloat.tree.LabelStmt;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MonitorStmt;
import edu.purdue.cs.bloat.tree.NegExpr;
import edu.purdue.cs.bloat.tree.NewArrayExpr;
import edu.purdue.cs.bloat.tree.NewExpr;
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
import edu.purdue.cs.bloat.tree.PhiJoinStmt;
import edu.purdue.cs.bloat.tree.RCExpr;
import edu.purdue.cs.bloat.tree.RetStmt;
import edu.purdue.cs.bloat.tree.ReturnAddressExpr;
import edu.purdue.cs.bloat.tree.ReturnExprStmt;
import edu.purdue.cs.bloat.tree.ReturnStmt;
import edu.purdue.cs.bloat.tree.SCStmt;
import edu.purdue.cs.bloat.tree.SRStmt;
import edu.purdue.cs.bloat.tree.ShiftExpr;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.SwitchStmt;
import edu.purdue.cs.bloat.tree.ThrowStmt;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.UCExpr;
import edu.purdue.cs.bloat.tree.ZeroCheckExpr;
/**
* NodeComparator is a class used to differentiate nodes in an expression tree.
*/
public class NodeComparator {
public static boolean DEBUG = false;
/**
* Determines whether or not two <tt>Node</tt>s are equal.
*/
public static boolean equals(final Node v, final Node w) {
class Bool {
boolean value = false;
}
;
final Bool eq = new Bool();
v.visit(new TreeVisitor() {
public void visitExprStmt(ExprStmt stmt) {
if (w instanceof ExprStmt) {
eq.value = true;
}
}
public void visitIfCmpStmt(IfCmpStmt stmt) {
if (w instanceof IfCmpStmt) {
IfCmpStmt s = (IfCmpStmt) w;
eq.value = stmt.trueTarget() == s.trueTarget()
&& stmt.falseTarget() == s.falseTarget()
&& stmt.comparison() == s.comparison();
}
}
public void visitIfZeroStmt(IfZeroStmt stmt) {
if (w instanceof IfZeroStmt) {
IfZeroStmt s = (IfZeroStmt) w;
eq.value = stmt.trueTarget() == s.trueTarget()
&& stmt.falseTarget() == s.falseTarget()
&& stmt.comparison() == s.comparison();
}
}
public void visitSCStmt(SCStmt stmt) {
if (w instanceof SCStmt) {
SCStmt s = (SCStmt) w;
eq.value = stmt.array() == s.array()
&& stmt.index() == s.index();
}
}
public void visitSRStmt(SRStmt stmt) {
if (w instanceof SRStmt) {
SRStmt s = (SRStmt) w;
eq.value = stmt.array() == s.array()
&& stmt.start() == s.start()
&& stmt.end() == s.end();
}
}
public void visitInitStmt(InitStmt stmt) {
if (w instanceof InitStmt) {
eq.value = true;
}
}
public void visitGotoStmt(GotoStmt stmt) {
if (w instanceof GotoStmt) {
GotoStmt s = (GotoStmt) w;
eq.value = stmt.target() == s.target();
}
}
public void visitLabelStmt(LabelStmt stmt) {
if (w instanceof LabelStmt) {
LabelStmt s = (LabelStmt) w;
eq.value = stmt.label().equals(s.label());
}
}
public void visitMonitorStmt(MonitorStmt stmt) {
if (w instanceof MonitorStmt) {
MonitorStmt s = (MonitorStmt) w;
eq.value = stmt.kind() == s.kind();
}
}
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
if (w instanceof PhiJoinStmt) {
eq.value = true;
}
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
if (w instanceof PhiCatchStmt) {
eq.value = true;
}
}
public void visitCatchExpr(CatchExpr expr) {
// Catches are not equivalent.
eq.value = false;
}
public void visitStackManipStmt(StackManipStmt stmt) {
if (w instanceof StackManipStmt) {
StackManipStmt s = (StackManipStmt) w;
eq.value = stmt.kind() == s.kind();
}
}
public void visitRetStmt(RetStmt stmt) {
if (w instanceof RetStmt) {
RetStmt s = (RetStmt) w;
eq.value = stmt.sub() == s.sub();
}
}
public void visitReturnExprStmt(ReturnExprStmt stmt) {
if (w instanceof ReturnExprStmt) {
eq.value = true;
}
}
public void visitReturnStmt(ReturnStmt stmt) {
if (w instanceof ReturnStmt) {
eq.value = true;
}
}
public void visitAddressStoreStmt(AddressStoreStmt stmt) {
if (w instanceof AddressStoreStmt) {
AddressStoreStmt s = (AddressStoreStmt) w;
eq.value = stmt.sub() == s.sub();
}
}
public void visitStoreExpr(StoreExpr expr) {
if (w instanceof StoreExpr) {
eq.value = true;
}
}
public void visitJsrStmt(JsrStmt stmt) {
if (w instanceof JsrStmt) {
JsrStmt s = (JsrStmt) w;
eq.value = stmt.sub() == s.sub();
}
}
public void visitSwitchStmt(SwitchStmt stmt) {
if (w instanceof SwitchStmt) {
eq.value = stmt == w;
}
}
public void visitThrowStmt(ThrowStmt stmt) {
if (w instanceof ThrowStmt) {
eq.value = true;
}
}
public void visitArithExpr(ArithExpr expr) {
if (w instanceof ArithExpr) {
ArithExpr e = (ArithExpr) w;
eq.value = e.operation() == expr.operation();
}
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
if (w instanceof ArrayLengthExpr) {
eq.value = true;
}
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
if (w instanceof ArrayRefExpr) {
eq.value = true;
}
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Calls are never equal.
eq.value = false;
}
public void visitCallStaticExpr(CallStaticExpr expr) {
// Calls are never equal.
eq.value = false;
}
public void visitCastExpr(CastExpr expr) {
if (w instanceof CastExpr) {
CastExpr e = (CastExpr) w;
eq.value = e.castType().equals(expr.castType());
}
}
public void visitConstantExpr(ConstantExpr expr) {
if (w instanceof ConstantExpr) {
ConstantExpr e = (ConstantExpr) w;
if (e.value() == null) {
eq.value = expr.value() == null;
} else {
eq.value = e.value().equals(expr.value());
}
}
}
public void visitFieldExpr(FieldExpr expr) {
if (w instanceof FieldExpr) {
FieldExpr e = (FieldExpr) w;
eq.value = e.field().equals(expr.field());
}
}
public void visitInstanceOfExpr(InstanceOfExpr expr) {
if (w instanceof InstanceOfExpr) {
InstanceOfExpr e = (InstanceOfExpr) w;
eq.value = e.checkType().equals(expr.checkType());
}
}
public void visitLocalExpr(LocalExpr expr) {
if (w instanceof LocalExpr) {
LocalExpr e = (LocalExpr) w;
eq.value = e.def() == expr.def();
}
}
public void visitNegExpr(NegExpr expr) {
if (w instanceof NegExpr) {
eq.value = true;
}
}
public void visitNewArrayExpr(NewArrayExpr expr) {
eq.value = false;
}
public void visitNewExpr(NewExpr expr) {
eq.value = false;
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
eq.value = false;
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
if (w instanceof ZeroCheckExpr) {
eq.value = true;
}
}
public void visitRCExpr(RCExpr expr) {
if (w instanceof RCExpr) {
eq.value = true;
}
}
public void visitUCExpr(UCExpr expr) {
if (w instanceof UCExpr) {
UCExpr e = (UCExpr) w;
eq.value = e.kind() == expr.kind();
}
}
public void visitReturnAddressExpr(ReturnAddressExpr expr) {
if (w instanceof ReturnAddressExpr) {
eq.value = true;
}
}
public void visitShiftExpr(ShiftExpr expr) {
if (w instanceof ShiftExpr) {
ShiftExpr e = (ShiftExpr) w;
eq.value = e.dir() == expr.dir();
}
}
public void visitStackExpr(StackExpr expr) {
if (w instanceof StackExpr) {
StackExpr e = (StackExpr) w;
eq.value = e.def() == expr.def();
}
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
if (w instanceof StaticFieldExpr) {
StaticFieldExpr e = (StaticFieldExpr) w;
eq.value = e.field().equals(expr.field());
}
}
public void visitNode(Node node) {
throw new RuntimeException("No method for " + node);
}
});
return eq.value;
}
/**
* Computes a hash code for a given <tt>Node</tt> based upon its type. The
* hash code of nodes that are composed of other nodes are based upon their
* composits.
*/
public static int hashCode(final Node node) {
class Int {
int value = 0;
}
;
final Int hash = new Int();
node.visit(new TreeVisitor() {
public void visitExprStmt(ExprStmt stmt) {
hash.value = 1;
}
public void visitIfCmpStmt(IfCmpStmt stmt) {
hash.value = stmt.comparison() + stmt.trueTarget().hashCode()
+ stmt.falseTarget().hashCode();
}
public void visitIfZeroStmt(IfZeroStmt stmt) {
hash.value = stmt.comparison() + stmt.trueTarget().hashCode()
+ stmt.falseTarget().hashCode();
}
public void visitInitStmt(InitStmt stmt) {
hash.value = 2;
}
public void visitGotoStmt(GotoStmt stmt) {
hash.value = stmt.target().hashCode();
}
public void visitLabelStmt(LabelStmt stmt) {
hash.value = stmt.label().hashCode();
}
public void visitMonitorStmt(MonitorStmt stmt) {
hash.value = stmt.kind();
}
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
hash.value = 3;
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
hash.value = 4;
}
public void visitCatchExpr(CatchExpr expr) {
// Catches are not equivalent.
hash.value = expr.hashCode();
}
public void visitStackManipStmt(StackManipStmt stmt) {
hash.value = stmt.kind();
}
public void visitRetStmt(RetStmt stmt) {
hash.value = 5;
}
public void visitReturnExprStmt(ReturnExprStmt stmt) {
hash.value = 6;
}
public void visitReturnStmt(ReturnStmt stmt) {
hash.value = 7;
}
public void visitAddressStoreStmt(AddressStoreStmt stmt) {
hash.value = 8;
}
public void visitStoreExpr(StoreExpr expr) {
hash.value = 9;
}
public void visitJsrStmt(JsrStmt stmt) {
hash.value = 10;
}
public void visitSwitchStmt(SwitchStmt stmt) {
hash.value = 11;
}
public void visitThrowStmt(ThrowStmt stmt) {
hash.value = 12;
}
public void visitArithExpr(ArithExpr expr) {
hash.value = expr.operation();
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
hash.value = 13;
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
hash.value = 14;
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Calls are never equal.
hash.value = expr.hashCode();
}
public void visitCallStaticExpr(CallStaticExpr expr) {
// Calls are never equal.
hash.value = expr.hashCode();
}
public void visitCastExpr(CastExpr expr) {
hash.value = expr.castType().hashCode();
}
public void visitConstantExpr(ConstantExpr expr) {
if (expr.value() == null) {
hash.value = 0;
} else {
hash.value = expr.value().hashCode();
}
}
public void visitFieldExpr(FieldExpr expr) {
hash.value = expr.field().hashCode();
}
public void visitInstanceOfExpr(InstanceOfExpr expr) {
hash.value = expr.checkType().hashCode();
}
public void visitLocalExpr(LocalExpr expr) {
if (expr.def() != null) {
hash.value = expr.def().hashCode();
} else {
hash.value = 0;
}
}
public void visitNegExpr(NegExpr expr) {
hash.value = 16;
}
public void visitNewArrayExpr(NewArrayExpr expr) {
hash.value = expr.hashCode();
}
public void visitNewExpr(NewExpr expr) {
hash.value = expr.hashCode();
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
hash.value = expr.hashCode();
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
hash.value = 15;
}
public void visitRCExpr(RCExpr expr) {
hash.value = 17;
}
public void visitUCExpr(UCExpr expr) {
hash.value = 18 + expr.kind();
}
public void visitReturnAddressExpr(ReturnAddressExpr expr) {
hash.value = 21;
}
public void visitSCStmt(SCStmt stmt) {
hash.value = 23;
}
public void visitSRStmt(SRStmt stmt) {
hash.value = 22;
}
public void visitShiftExpr(ShiftExpr expr) {
hash.value = expr.dir();
}
public void visitStackExpr(StackExpr expr) {
if (expr.def() != null) {
hash.value = expr.def().hashCode();
} else {
hash.value = 0;
}
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
hash.value = expr.field().hashCode();
}
public void visitNode(Node node) {
throw new RuntimeException("No method for " + node);
}
});
return hash.value;
}
}

@ -0,0 +1,978 @@
/*
* Class: Peephole
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.util.Assert;
import java.util.*;
/**
* Performs some peephole optimizations such as loads and stores and removes
* unreachable instructions.
*/
public class Peephole implements Optimization {
public static boolean DEBUG = false;
public String traceMessage(String dateString) {
return null;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
public void transform(MethodState state) {
this.transform(state.methodGen(), true);
}
/**
* Perform peephole optimizations on the bytecodes in a method. Peephole
* optimizations look at two consecutive instructions and try to perform
* some simple optimization. For instance, a push followed by a pop is
* uninteresting, so both of those instructions can be removed.
*
* <p>
*
* After the peephole optimizations are performed a final phase removes
* instructions that are not reachable. These instructions reside in basic
* blocks whose starting label is never jumped to.
*/
// Peephole can work on any bytecode sequence it does not have to be a
// result of calls
// to CodeGenerator. However, if Peephole will need to have labels denoting
// the start
// of basic blocks, if the code is not the result of output from
// CodeGenerator then labels
// will not be intact set "labels" to false if this is the case and they can
// be placed using
// FlowGraph.buildBLOATInstructionList(MethodGen) --Arrin
public void transform(MethodGen method, boolean labels) {
if (DEBUG) {
System.out.println("Peephole optimizing " + method);
}
// Map between labels and the instruction that they label
Map targets = new LinkedHashMap();
LinkedList jumps = new LinkedList(); // Jump instructions
Instruction next = null;
InstructionList code = method.getInstructionList();
// Do we need to build the labels are they already intact?
if (!labels)
FlowGraph.buildBLOATInstructionList(method);
InstructionHandle ih = null;
// Go backwards so we can eliminate redundant loads and stores
// in one pass. During the pass collect the locations of labels.
boolean canFilter = true;
CODE: for (ih = code.getEnd(); ih != code.getStart(); ih = ih.getPrev()) {
if (FlowGraph.label(ih)) {
targets.put(ih, ih.getInstruction());
}
// All items are Instructions now
Instruction inst = ih.getInstruction();
Filter peep = null;
// Have we seen a label that starts a block? (i.e. is a target)
boolean seenLabel = false;
if (inst instanceof GotoInstruction) {
// Look at the instructions following the goto. If an
// instruction follows and no label (that starts a block)
// has been seen, the instruction is dead and can be
// removed. If the target of the goto follows the goto
// instruction, the goto is useless and is removed.
InstructionHandle target = ((GotoInstruction) inst).getTarget();
for (InstructionHandle j = ih.getNext(); j != null; j = j
.getNext()) {
// Replace
// goto L
// L: inst
// with
// L: inst
//
if (FlowGraph.label(j)) {
// if (((Label) t).startsBlock()) {
// All labels start a block now
seenLabel = true;
if (target.equals(j)) {
InstructionHandle toDelete = ih;
ih = ih.getNext();
try {
code.delete(toDelete);
next = null;
} catch (TargetLostException tle) {
InstructionHandle[] losttargets = tle
.getTargets();
for (int i = 0; i < losttargets.length; i++) {
InstructionTargeter[] targeters = losttargets[i]
.getTargeters();
for (int k = 0; k < targeters.length; k++)
targeters[k].updateTarget(
losttargets[i], j);
}
// Redirect Lost targeters
}
continue CODE;
}
if (Peephole.DEBUG)
System.out.println("Not a target instruction : "
+ j.getInstruction());
// Now we want to look at the instruction
// continue;
}
// Replace
// goto L
// this is unreachable
// M: inst (M is a different label from L!)
// with
// goto L
// M: inst
//
// if (!FlowGraph.label(j)) {
if (seenLabel) {
break;
}
InstructionHandle j2 = j;
j = j.getPrev();
try {
code.delete(j2); // Delete an unreachable instruction
} catch (TargetLostException tle) {
System.out.println("Got a lost Target!!!!!!!");
// fail quitely
}
// }
}
}
if (inst instanceof GotoInstruction || inst instanceof Select
|| inst instanceof IfInstruction) {
jumps.add(ih);
}
// Performs some peephole optimizations using the filter
// method that returns an instance of the Filter class. The
// filter method looks at two consecutive instructions and
// determines whether or not something about them can be
// changed. For instance, if a push is followed by a pop,
// both instructions are useless and can be eliminated. The
// contents of the Filter object represents the effects of the
// peephole optimization.
if (next != null && canFilter) {
peep = filter(inst, next, method);
}
if (peep != null) {
if (Peephole.DEBUG) {
if (peep.replace.length == 0) {
System.out.println("eliminate " + ih.getInstruction()
+ "-" + ih.getNext().getInstruction());
} else {
System.out.println("replace " + ih.getInstruction()
+ "-" + ih.getNext().getInstruction());
System.out.println(" with");
for (int j = 0; j < peep.replace.length; j++) {
System.out.println(" " + peep.replace[j]);
}
}
}
InstructionHandle oldIh = ih;
ih = ih.getPrev();
InstructionHandle redirectTo = ih.getNext().getNext();
// if no Instruction is added redirect to after the deleted
// instructions
if (ih == null) {// we are at the start of the
// InstructionList
// Add instructions resulting from peephole optimizations
for (int j = peep.replace.length - 1; j >= 0; j--) {
if (peep.replace[j] instanceof BranchInstruction)
redirectTo = code
.insert((BranchInstruction) peep.replace[j]);
else
// UGH BCEL treats Branch instructions differently
redirectTo = code.insert(peep.replace[j]);
// break;
}
} else {
for (int j = peep.replace.length - 1; j >= 0; j--) {
if (peep.replace[j] instanceof BranchInstruction)
redirectTo = code.append(ih,
(BranchInstruction) peep.replace[j]);
else
// UGH BCEL treats Branch instructions differently
redirectTo = code.append(ih, peep.replace[j]);
}
}
try {
// Remove old instructions
code.delete(oldIh.getNext());
code.delete(oldIh);
} catch (TargetLostException tle) {
FlowGraph.setLabel(redirectTo); // reinstate as a label.
InstructionHandle[] losttargets = tle.getTargets();
for (int i = 0; i < losttargets.length; i++) {
InstructionTargeter[] targeters = losttargets[i]
.getTargeters();
for (int j = 0; j < targeters.length; j++)
targeters[j].updateTarget(losttargets[i],
redirectTo);
}
// Redirect Lost targeters
}
ih = ih.getNext();// This should be one of the added
// instructions if one was added.
if (ih != null && !FlowGraph.label(ih)) {
next = ih.getInstruction();
} else {
// No more instructions, or next thing is a label
next = null;
}
} else {
if (ih != null && !FlowGraph.label(ih)) {
next = ih.getInstruction();
} else {
next = null;
}
// Filter didn't find any peephole optimizations, skip to
// next pair of instructions.
}
}
if (DEBUG) {
System.out.println("Peephole optimizing removing GOTOs");
}
// Replace the target of jumps to gotos with the goto target.
// Replace gotos to unconditional jumps with the unconditional jump.
while (!jumps.isEmpty()) {
InstructionHandle iHandle = (InstructionHandle) jumps.removeFirst();
InstructionHandle target;
if ((iHandle.getInstruction() instanceof GotoInstruction)
|| (iHandle.getInstruction() instanceof IfInstruction)) {
BranchInstruction inst = (BranchInstruction) iHandle
.getInstruction();
target = inst.getTarget();
if (target != null) {
Instruction targetInst = target.getInstruction();
if (targetInst instanceof GotoInstruction
&& !(((GotoInstruction) targetInst).getTarget()
.equals(inst.getTarget()))) {
// IF THIS WASN'T TRUE WOULDN'T IT MEAN WE HAVE A GOTO
// DIRECTED TO JUMP TO ITSELF?
if (Peephole.DEBUG) {
System.out.println("replace " + inst);
}
inst.setTarget(((GotoInstruction) targetInst)
.getTarget());
if (Peephole.DEBUG) {
System.out.println(" with " + inst);
}
jumps.add(iHandle);
} else if ((inst instanceof GotoInstruction)
&& (targetInst instanceof Select ||
// targetInst instanceof ReturnInstruction ||
targetInst instanceof ATHROW)) {
if (Peephole.DEBUG) {
System.out.println("replace " + inst);
}
iHandle.setInstruction((BranchInstruction) targetInst
.copy());
// THIS MIGHT BE BAD copy() IS A SHALLOW COPY!!
if (Peephole.DEBUG) {
System.out.println(" with " + targetInst);
}
}
}
}
}
// Remove unreachable code.
removeUnreachable(method, code);
Iterator iterhandles = method.getInstructionList().iterator();
while (iterhandles.hasNext()) {
ih = (InstructionHandle) iterhandles.next();
ih.removeAttribute("Label");
}
method.removeNOPs();
method.getInstructionList().setPositions();
method.setMaxStack();
method.setMaxLocals();
method.update();
if (Peephole.DEBUG) {
System.out.println("END PEEPHOLE--------------------------------");
}
}
/**
* Iterate over the code in the method and determine which labels begin
* blocks that are reachable. The code in blocks that are not reachable is
* removed.
*/
// TODO: Currently, ALL ret targets are marked reachable from a
// single ret. Correct this by looking at the local variables.
private void removeUnreachable(MethodGen method, InstructionList code) {
// Maps Labels to their instruction position
Map labelPos = new LinkedHashMap();
// Collect all the ret targets.
Iterator iter = code.iterator();
int i = 0;
while (iter.hasNext()) {
InstructionHandle ce = (InstructionHandle) iter.next();
if (FlowGraph.label(ce)) {
labelPos.put(ce, new Integer(i));
}
i++;
}
// Visit the blocks depth-first.
// Stack of Labels that begin blocks that have been visited
Set visited = new LinkedHashSet();
// Stack of Labels that begin blocks that have not been visited
Stack stack = new Stack();
InstructionHandle label; // Current label
if (code.getLength() > 0) {
// Start with the label of the first block
label = (InstructionHandle) code.getStart();
visited.add(label);
stack.push(label);
}
CodeExceptionGen[] excptns = method.getExceptionHandlers();
for (i = 0; i < excptns.length; i++) {
// All exception handlers are considered to be live
visited.add(excptns[i].getHandlerPC());
stack.push(excptns[i].getHandlerPC());
}
while (!stack.isEmpty()) {
label = (InstructionHandle) stack.pop();
Integer labelIndex = (Integer) labelPos.get(label);
Assert.isTrue(labelIndex != null, "Index of label_"
+ label.getPosition() + " not found");
InstructionHandle blockIter = label;
while (blockIter != null && blockIter.getNext() != null) {
// Iterate over the code in the block. If we encounter
// instructions that change execution (i.e. go to another
// block), add the Label of the target of the jump to the
// stack if it is not already present.
blockIter = blockIter.getNext();
Instruction inst = blockIter.getInstruction();
if (!FlowGraph.label(blockIter)) {
if (inst instanceof ReturnInstruction
|| inst instanceof ATHROW) {
// We've reached the end of the block, but we don't know
// which block will be executed next.
break;
} else if (inst instanceof IfInstruction
|| inst instanceof JsrInstruction) {
// We've reached the end of the block, add the Label of
// the next block to be executed to the list. It's a
// conditional jump, so don't break. The rest of the
// code in the block is not necessarily dead.
label = ((BranchInstruction) inst).getTarget();
if (!visited.contains(label)) {
visited.add(label);
stack.push(label);
}
// Fall through.
} else if (inst instanceof GotoInstruction) {
// Add next block to work list.
label = ((GotoInstruction) inst).getTarget();
if (!visited.contains(label)) {
visited.add(label);
stack.push(label);
}
break;
} else if (inst instanceof RET) {
// The ret targets were handled by the jsr.
break;
} else if (inst instanceof Select) {
// A switch. Add all possible targets of the switch to
// the worklist.
Select sw = (Select) inst;
label = sw.getTarget();
if (!visited.contains(label)) {
visited.add(label);
stack.push(label);
}
InstructionHandle[] targets = sw.getTargets();
for (int j = 0; j < targets.length; j++) {
label = targets[j];
if (!visited.contains(label)) {
visited.add(label);
stack.push(label);
}
}
break;
}
} else if (FlowGraph.label(blockIter)) {
label = blockIter;
visited.add(label);
}
}
}
if (DEBUG) {
System.out.println("Done finding unreachable instructions");
}
boolean reachable = false;
iter = code.iterator();
// Remove unreachable instructions
while (iter.hasNext()) {
InstructionHandle ce = (InstructionHandle) iter.next();
if (FlowGraph.label(ce)) {
reachable = visited.contains(ce);
// Don't remove unreachable labels, only instructions.
}
if (!reachable) {
if (Peephole.DEBUG) {
System.out.println("Removing unreachable " + ce);
}
iter.remove();
}
}
}
/**
* Filter represents a set of instructions that result from a peephole
* optimizations. For instance, when uninteresting instructions are removed,
* a Filter object with an empty "replace" array will be returned by the
* below filter method.
*/
static class Filter {
Instruction[] replace;
boolean[] labels;
Filter() {
this.replace = new Instruction[0];
}
Filter(Instruction replace) {
this.replace = new Instruction[] { replace };
}
Filter(Instruction replace1, Instruction replace2) {
this.replace = new Instruction[] { replace1, replace2 };
}
}
/**
* Filter a pair of instructions. That is, do a peephole optimization on two
* consecutive instructions. For instance, if a push is followed by a pop,
* both instructions can be eliminated. The <tt>Filter</tt> object that is
* returned specifies what instruction(s), if any, should replace the two
* instructions that are the parameters to this method.
*
* @param first
* The first instruction.
* @param second
* The second instruction.
* @return A list of instructions to replace the two instructions with, or
* null, if the instructions should be left as is.
*/
private Filter filter(Instruction first, Instruction second,
MethodGen method) {
// switch (second.opcodeClass()) {
// swap means nothing if it's after a dup.
// (goodbye means nothing when it's all for show
// so stop pretending you've somewhere else to go.)
// case opcx_swap:
if (second instanceof SWAP) {
// Elminate swap-swap
if (first instanceof SWAP)
return new Filter();
// swap means nothing if it's after a dup.
// (goodbye means nothing when it's all for show
// so stop pretending you've somewhere else to go.)
if (first instanceof DUP) {
return new Filter(first);
}
} else if (second instanceof POP) {// Eliminate push-pop.
// Eliminate push-pop.
// switch (first.opcodeClass()) {
if (first instanceof LDC) {
LDC f = (LDC) first;
// Make sure things being popped off is not wide (we're
// dealing with a pop not a pop2).
Assert.isTrue(!(f.getType(method.getConstantPool())
.equals(Type.LONG))
&& !(f.getType(method.getConstantPool())
.equals(Type.DOUBLE)),
"Cannot pop a 2-word operand");
return new Filter();
} else if ((first instanceof ILOAD) || (first instanceof FLOAD)
|| (first instanceof ALOAD) || (first instanceof DUP)) {
// Eliminate the load and the pop.
return new Filter();
} else if (first instanceof DUP_X1) {
// Replace dup_x1-pop with swap
// (As if this is really likely to happen ;) <-- Nate made a
// joke!
System.out.println("HERE0 inserting SWAP");
return new Filter(new SWAP());
}
} else if (second instanceof POP2) {
if (first instanceof LDC) {
LDC f = (LDC) first;
Assert.isTrue((f.getType(method.getConstantPool())
.equals(Type.LONG))
|| (f.getType(method.getConstantPool())
.equals(Type.DOUBLE)),
"Cannot pop2 a 1-word operand");
return new Filter();
} else if ((first instanceof LLOAD) || (first instanceof DLOAD)
|| (first instanceof DUP2)) {
// Eliminate push and pop
return new Filter();
}
} else if (second instanceof ISTORE) {
StoreInstruction secnd = (StoreInstruction) second;
// Eliminate load-store to same location.
if (first instanceof ILOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter();
}
}
} else if (second instanceof FSTORE) {
StoreInstruction secnd = (StoreInstruction) second;
if (first instanceof FLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter();
}
}
} else if (second instanceof ASTORE) {
StoreInstruction secnd = (StoreInstruction) second;
if (first instanceof ALOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter();
}
}
} else if (second instanceof LSTORE) {
StoreInstruction secnd = (StoreInstruction) second;
if (first instanceof LLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter();
}
}
} else if (second instanceof DSTORE) {
StoreInstruction secnd = (StoreInstruction) second;
if (first instanceof DLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter();
}
}
} else if (second instanceof ReturnInstruction) {
// THIS APPLIES FOR RETURN TOO RIGHT?
// Replace store-return with return. Remember that upon return
// all local variables revert to their pre-call values, so any
// stores are destroyed.
if (first instanceof StoreInstruction) {
return new Filter(second);
}
} else if (second instanceof IADD) {
// Replace ineg-iadd with isub
if (first instanceof INEG) {
return new Filter(new ISUB());
}
} else if (second instanceof ISUB) {
// Replace ineg-isub with iadd
if (first instanceof INEG) {
return new Filter(new IADD());
}
} else if (second instanceof LADD) {
// Replace lneg-ladd with lsub
if (first instanceof LNEG) {
return new Filter(new LSUB());
}
} else if (second instanceof LSUB) {
// Replace lneg-lsub with ladd
if (first instanceof LNEG) {
return new Filter(new LADD());
}
} else if (second instanceof IF_ICMPEQ) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmpeq with ifeq
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFEQ(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ICMPNE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmpne with ifne
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFNE(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ICMPLT) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmplt with iflt
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFLT(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ICMPGE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmpge with ifge
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFGE(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ICMPGT) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmpgt with ifgt
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFGT(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ICMPLE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-if_icmple with ifle
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new IFLE(secnd.getTarget()));
}
}
}
} else if (second instanceof IF_ACMPEQ) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc null-if_acmpeq with ifnull
if (first instanceof LDC) {
LDC frst = (LDC) first;
if (frst.getValue(method.getConstantPool()) == null) {
return new Filter(new IFNULL(secnd.getTarget()));
}
}
} else if (second instanceof IF_ACMPNE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc null-if_acmpne with ifnonnull
if (first instanceof LDC) {
LDC frst = (LDC) first;
if (frst.getValue(method.getConstantPool()) == null) {
return new Filter(new IFNONNULL(secnd.getTarget()));
}
}
} else if (second instanceof IFEQ) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc 0-ifeq with goto and eliminate ldc !0-ifeq
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() == 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
} else if (second instanceof IFNE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc !0-ifne with goto and eliminate ldc 0-ifne
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() != 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
} else if (second instanceof IFLT) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc <0-iflt with goto and eliminate ldc >=0-iflt
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() < 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
} else if (second instanceof IFGE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc >=0-ifge with goto and eliminate ldc <0-ifge
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() >= 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
} else if (second instanceof IFGT) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc >0-ifgt with goto and eliminate ldc <=0-ifgt
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() > 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
} else if (second instanceof IFLE) {
BranchInstruction secnd = (BranchInstruction) second;
// Replace ldc <=0-ifle with goto and eliminate ldc >0-ifle
if (first instanceof LDC) {
LDC frst = (LDC) first;
Object op = frst.getValue(method.getConstantPool());
if (op instanceof Integer) {
if (((Integer) op).intValue() <= 0) {
return new Filter(new GOTO(secnd.getTarget()));
} else {
return new Filter();
}
}
}
}
if (second instanceof StoreInstruction) {
StoreInstruction secnd = (StoreInstruction) second;
// Replace store-store to same location with pop-store.
if (first instanceof StoreInstruction) {
StoreInstruction frst = (StoreInstruction) first;
if ((frst instanceof LSTORE) || (frst instanceof DSTORE)) {
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new POP2(), first);
}
} else {
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new POP(), first);
}
}
}
}
// Replace store-load with dup-store.
// Replace load-load with load-dup.
if (second instanceof ILOAD) {
LoadInstruction secnd = (LoadInstruction) second;
if (first instanceof ISTORE) {
StoreInstruction frst = (StoreInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new DUP(), first);
}
}
if (first instanceof ILOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(first, new DUP());
}
}
} else if (second instanceof FLOAD) {
LoadInstruction secnd = (LoadInstruction) second;
if (first instanceof FSTORE) {
StoreInstruction frst = (StoreInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new DUP(), first);
}
}
if (first instanceof FLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(first, new DUP());
}
}
} else if (second instanceof ALOAD) {
LoadInstruction secnd = (LoadInstruction) second;
if (first instanceof ASTORE) {
StoreInstruction frst = (StoreInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new DUP(), first);
}
}
if (first instanceof ALOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(first, new DUP());
}
}
} else if (second instanceof LLOAD) {
LoadInstruction secnd = (LoadInstruction) second;
if (first instanceof LSTORE) {
StoreInstruction frst = (StoreInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new DUP2(), first);
}
}
if (first instanceof LLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(first, new DUP2());
}
}
} else if (second instanceof DLOAD) {
LoadInstruction secnd = (LoadInstruction) second;
if (first instanceof DSTORE) {
StoreInstruction frst = (StoreInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(new DUP2(), first);
}
}
if (first instanceof DLOAD) {
LoadInstruction frst = (LoadInstruction) first;
if (frst.getIndex() == secnd.getIndex()) {
return new Filter(first, new DUP2());
}
}
}
return null;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,359 @@
/*
* Class: SideEffectChecker
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.editor.EditorContext;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ArrayLengthExpr;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.CallMethodExpr;
import edu.purdue.cs.bloat.tree.CallStaticExpr;
import edu.purdue.cs.bloat.tree.CastExpr;
import edu.purdue.cs.bloat.tree.CatchExpr;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MonitorStmt;
import edu.purdue.cs.bloat.tree.NewArrayExpr;
import edu.purdue.cs.bloat.tree.NewExpr;
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr;
import edu.purdue.cs.bloat.tree.RCExpr;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.UCExpr;
import edu.purdue.cs.bloat.tree.ZeroCheckExpr;
/**
* <tt>SideEffectChecker</tt> traverses a tree and determines if a node has
* any side effects such as changing the stack, calling a function, or
* performing a residency check. The side effects are represented by an integer
* whose bits represent a certain kind of side effect.
*
* <p>
*
* <Tt>SideEffectChecker</tt> is a <tt>TreeVisitor</tt>. The way it works
* is that after a <tt>SideEffectChecker</tt> is reset, an expression tree
* <tt>Node</tt> is visited to determine whether or not it has side effects.
* Neat.
*/
public class SideEffectChecker extends TreeVisitor {
private int sideEffects = 0;
public static final int STACK = (1 << 0);
public static final int THROW = (1 << 1);
public static final int CALL = (1 << 2);
public static final int SYNC = (1 << 3);
public static final int ALLOC = (1 << 4); // Allocates memory
public static final int RC = (1 << 5);
public static final int UC = (1 << 6);
public static final int STORE = (1 << 7);
public static final int ALIAS = (1 << 8);
public static final int VOLATILE = (1 << 9);
private EditorContext context;
/**
* Constructor. The <tt>Context</tt> is needed to determine whether or not
* a field is VOLATILE, etc.
*/
public SideEffectChecker(EditorContext context) {
this.context = context;
}
public int sideEffects() {
return sideEffects;
}
public boolean hasSideEffects() {
return sideEffects != 0;
}
public void reset() {
sideEffects = 0;
}
public void visitStoreExpr(StoreExpr expr) {
sideEffects |= STORE;
expr.visitChildren(this);
}
public void visitLocalExpr(LocalExpr expr) {
if (expr.isDef()) {
sideEffects |= STORE;
}
expr.visitChildren(this);
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
sideEffects |= THROW;
expr.visitChildren(this);
}
public void visitRCExpr(RCExpr expr) {
sideEffects |= RC;
expr.visitChildren(this);
}
public void visitUCExpr(UCExpr expr) {
sideEffects |= UC;
expr.visitChildren(this);
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
sideEffects |= THROW | ALLOC;
expr.visitChildren(this);
}
public void visitNewArrayExpr(NewArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
sideEffects |= THROW | ALLOC;
expr.visitChildren(this);
}
public void visitCatchExpr(CatchExpr expr) {
// Stack change
sideEffects |= STACK;
expr.visitChildren(this);
}
public void visitNewExpr(NewExpr expr) {
// Memory allocation
sideEffects |= ALLOC;
expr.visitChildren(this);
}
public void visitStackExpr(StackExpr expr) {
// Stack change
sideEffects |= STACK;
if (expr.isDef()) {
sideEffects |= STORE;
}
expr.visitChildren(this);
}
public void visitCastExpr(CastExpr expr) {
// ClassCastException
if (expr.castType() instanceof ReferenceType) {
sideEffects |= THROW;
}
expr.visitChildren(this);
}
public void visitArithExpr(ArithExpr expr) {
// DivideByZeroException -- handled by ZeroCheckExpr
/*
* if (expr.operation() == ArithExpr.DIV || expr.operation() ==
* ArithExpr.REM) {
*
* if (expr.type().isIntegral() || expr.type().equals(Type.LONG)) {
* sideEffects |= THROW; } }
*/
expr.visitChildren(this);
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
// NullPointerException
sideEffects |= THROW;
expr.visitChildren(this);
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
// NullPointerException, ArrayIndexOutOfBoundsException,
// ArrayStoreException
sideEffects |= THROW;
if (expr.isDef()) {
sideEffects |= STORE;
}
sideEffects |= ALIAS;
expr.visitChildren(this);
}
public void visitFieldExpr(FieldExpr expr) {
// NullPointerException -- handled by ZeroCheckExpr
/*
* sideEffects |= THROW;
*/
if (expr.isDef()) {
sideEffects |= STORE;
}
MemberRef field = expr.field();
try {
try {
ReferenceType type = field.declaringClass();
if (type instanceof ArrayType) {// TODO
Type elementType = ((ArrayType) type).getElementType();
if (elementType instanceof BasicType) {
return; // Already loaded
}
type = (ObjectType) elementType;
}
JavaClass jc = context.loadClass(((ObjectType) type)
.getClassName());
Field[] fields = jc.getFields();
Field e = null;
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(field.name())
&& fields[i].getType().equals(field.type())) {
e = fields[i];
break;
}
}
if (e == null)
throw new NoSuchFieldException("field :" + field
+ "not found");
if (!e.isFinal()) {
sideEffects |= ALIAS;
}
if (e.isVolatile()) {
sideEffects |= VOLATILE;
}
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
// context.release(e.fieldInfo());
} catch (NoSuchFieldException e) {
// A field wasn't found. Silently assume it's not final and
// is volatile.
sideEffects |= ALIAS;
sideEffects |= VOLATILE;
}
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe.getMessage());
}
expr.visitChildren(this);
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
if (expr.isDef()) {
sideEffects |= STORE;
}
MemberRef field = expr.field();
try {
try {
ReferenceType type = field.declaringClass();
if (type instanceof ArrayType) {// TODO
Type elementType = ((ArrayType) type).getElementType();
if (elementType instanceof BasicType) {
return; // Already loaded
}
type = (ObjectType) elementType;
}
JavaClass jc = context.loadClass(((ObjectType) type)
.getClassName());
Field e = null;
Field[] fields = jc.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(field.name())
&& fields[i].getType().equals(field.type())) {
e = fields[i];
break;
}
}
if (e == null)
throw new NoSuchFieldException("field :" + field
+ "not found");
if (e.isVolatile()) {
sideEffects |= VOLATILE;
}
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
// context.release(e.fieldInfo());
} catch (NoSuchFieldException e) {
// A field wasn't found. Silently assume it's volatile.
sideEffects |= VOLATILE;
}
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe.getMessage());
}
expr.visitChildren(this);
}
public void visitCallStaticExpr(CallStaticExpr expr) {
// Call
sideEffects |= THROW | CALL;
expr.visitChildren(this);
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Call
sideEffects |= THROW | CALL;
expr.visitChildren(this);
}
public void visitMonitorStmt(MonitorStmt stmt) {
// Synchronization
sideEffects |= THROW | SYNC;
stmt.visitChildren(this);
}
public void visitStackManipStmt(StackManipStmt stmt) {
// Stack change
sideEffects |= STACK;
stmt.visitChildren(this);
}
}

@ -0,0 +1,327 @@
/*
* Class: StackOpt
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.codegen.CodeGenerator;
import edu.purdue.cs.bloat.editor.InstructionAdapter;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.tree.Node;
public class StackOpt extends InstructionAdapter implements Optimization {
int stackHeight;
int minStackHeight;
static final boolean DEBUG = false;
public void transform(MethodState state) {
// generate code without doing liveness or register allocation
CodeGenerator codegen = new CodeGenerator(state);
codegen.replacePhis().generateCode();
// do stack optimization on the bytecode
state.commitChanges();
transform(state.methodGen());
state.rebuildFlowGraph();
}
// StackOpt needs use and definition and label information to perform
// transformations.
// Consequently CodeGenerator must have been run to produce the code
// supplied to StackOpt.transform.
// Because of this I assume that labels and use and definition
// information are in place.
// This is currently implemented using attributes in InstructionHandles,
// the keys being "Label" and
// "Def". --Arrin
private void transform(MethodGen method) {
for (InstructionHandle i = method.getInstructionList().getEnd(); i != null; // && i
// !=
// method.getInstructionList().getStart();
i = i.getPrev()) {
Instruction inst = i.getInstruction();
boolean isWide;
if (inst instanceof LoadInstruction) {
isWide = (((LoadInstruction) inst).getType(
method.getConstantPool()).getSize() == 2);
} else if (isArrayLoadInstruction(inst)) {
isWide = (((ArrayInstruction) inst).getType(
method.getConstantPool()).getSize() == 2);
} else {
continue;
}
if (DEBUG)
System.out.println("Considering: " + i);
stackHeight = 0;
boolean seenLabel = FlowGraph.label(i); // If 'i' is a label we
// don't do anything.
for (InstructionHandle j = i.getPrev();; j = j.getPrev()) {
// stop at the begining of the code or a basic block.
// As Labels are also instructions
if (j == null || seenLabel)
break;
if (stackHeight == -1
&& ((hasSameDef(i, j) && isLoadInstruction(j)) || dupRun(
j, i))) {
if (forwardCountCheck(method, j, i, -1)) {
// found a type 0 relation with a load
if (DEBUG) {
System.out.println("load type 0: " + j + " " + i);
}
if (isWide) {
method.getInstructionList().append(j, new DUP2());
} else {
method.getInstructionList().append(j, new DUP());
// add dup
}
i.setInstruction(new NOP());
// TODO: Why is deleting this a problem?
// I would have deleted it but it seems to cause all
// sorts of evil
}
break; // done, even if final check failed.
} else if (stackHeight == 0 && hasSameDef(i, j)) {
if (isStoreInstruction(j)) {
if (forwardCountCheck(method, j, i, 0)) {
// found a type 0 with a store
if (DEBUG) {
System.out.println("store type 0: " + j + " "
+ i);
}
if (isWide) {
method.getInstructionList().append(j,
j.getInstruction());
j.setInstruction(new DUP2());
} else {
method.getInstructionList().append(j,
j.getInstruction());
j.setInstruction(new DUP());
}
i.setInstruction(new NOP());
// I would have deleted it but it seems to cause
// all sorts of evil
}
break;
} else if (isLoadInstruction(j) && !isWide) {
// can't do type 1s with wides.
if (forwardCountCheck(method, j, i, -1)) {
// found a type 1 with a load
if (DEBUG)
System.out.println("load type 1: " + j + " "
+ i);
method.getInstructionList().append(j, new DUP());
System.out.println("HERE1 inserting SWAP");
i.setInstruction(new SWAP());
}
break;
}
} else if (stackHeight == 1 && hasSameDef(i, j)) {
if (isStoreInstruction(j) && !isWide) { // can't do type 1
// with wides
if (forwardCountCheck(method, j, i, 0)) {
// type 1 for stores
if (DEBUG)
System.out.println("store type 1: " + j + " "
+ i);
method.getInstructionList().append(j,
j.getInstruction());
j.setInstruction(new DUP());
System.out.println("HERE2 inserting SWAP");
i.setInstruction(new SWAP());
}
break;
}
}
heightChange(method, j.getInstruction());
if (FlowGraph.label(j)) {
seenLabel = true;
}
}
}
method.removeNOPs();
method.getInstructionList().setPositions();
if (DEBUG) {
System.out.println("Method:");
System.out.println(method);
for (InstructionHandle ih = method.getInstructionList().getStart(); ih != null; ih = ih
.getNext()) {
if (FlowGraph.label(ih))
System.out.print("(L)");
else
System.out.print(" ");
System.out.print(" " + ih.getPosition() + ": "
+ ih.getInstruction());
if (ih.getAttribute("Def") != null)
System.out.print("(" + ih.getAttribute("Def") + ")");
System.out.println("");
}
// System.out.println(method.getMethod().getCode());
System.out.println();
System.out.println("LocalVariables: ");
LocalVariableGen[] locals = method.getLocalVariables();
for (int i = 0; i < locals.length; i++) {
System.out.println(" " + locals[i]);
}
System.out.println("LocalVariable size: " + method.getMaxLocals());
CodeExceptionGen[] excptns = method.getExceptionHandlers();
if (excptns != null) {
System.out.println("ExceptionHandlers: ");
for (int j = 0; j < excptns.length; j++)
System.out.println(" " + excptns[j]);
}
}
method.setMaxStack();
method.setMaxLocals();
method.update();
}
boolean forwardCountCheck(MethodGen m, InstructionHandle j,
InstructionHandle i, int bound) {
stackHeight = 0;
minStackHeight = 0;
for (InstructionHandle k = j.getNext(); k != i; k = k.getNext()) {
heightChange(m, k.getInstruction());
if (minStackHeight < bound)
return false;
}
return true;
}
boolean dupRun(InstructionHandle j, InstructionHandle i) {
InstructionHandle k = j;
Instruction inst = k.getInstruction();
if (!(inst instanceof DUP))
return false;
do {
k = k.getPrev();
inst = k.getInstruction();
if (isLoadInstruction(inst) && hasSameDef(i, k)) {
return true;
}
} while (!FlowGraph.label(k) && k.getInstruction() instanceof DUP);
return (isLoadInstruction(inst)) && hasSameDef(i, k);
}
void heightChange(MethodGen method, Instruction inst) {
stackHeight = stackHeight - inst.consumeStack(method.getConstantPool());
if (stackHeight < minStackHeight)
minStackHeight = stackHeight;
stackHeight = stackHeight + inst.produceStack(method.getConstantPool());
}
private boolean hasSameDef(InstructionHandle i, InstructionHandle j) {
Node iDef = (Node) i.getAttribute("Def");
Node jDef = (Node) j.getAttribute("Def");
return ((iDef != null) && (jDef != null) && iDef == jDef);
}
public String traceMessage(String dateString) {
return " New stack optimization: " + dateString;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
private static boolean isLoadInstruction(InstructionHandle handle) {
return isLoadInstruction(handle.getInstruction());
}
private static boolean isLoadInstruction(Instruction inst) {
return inst instanceof LoadInstruction || isArrayLoadInstruction(inst);
}
private static boolean isArrayLoadInstruction(Instruction inst) {
return inst instanceof IALOAD || inst instanceof FALOAD
|| inst instanceof AALOAD || inst instanceof BALOAD
|| inst instanceof CALOAD || inst instanceof LALOAD
|| inst instanceof DALOAD || inst instanceof SALOAD;
}
private static boolean isStoreInstruction(InstructionHandle handle) {
return isStoreInstruction(handle.getInstruction());
}
private static boolean isStoreInstruction(Instruction inst) {
return inst instanceof StoreInstruction
|| isArrayStoreInstruction(inst);
}
private static boolean isArrayStoreInstruction(Instruction inst) {
return inst instanceof IASTORE || inst instanceof FASTORE
|| inst instanceof AASTORE || inst instanceof BASTORE
|| inst instanceof CASTORE || inst instanceof LASTORE
|| inst instanceof DASTORE || inst instanceof SASTORE;
}
}

@ -0,0 +1,76 @@
/*
* Class: StackOptimization
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import java.util.Iterator;
import java.util.List;
import edu.purdue.cs.bloat.cfg.Block;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
/**
* This is the old stack optimizer. The actual optimization stuff is in
* tree/StackOptimizationData.java, this class just provides a convenient plugin
* interface to it.
*
* This is completely unrelated to StackOpt.
*/
public class StackOptimization implements Optimization {
public String traceMessage(String dateString) {
return " Old stack optimization: " + dateString;
}
public String preDebugMessage() {
return null;
}
public String postDebugMessage() {
return null;
}
public void transform(MethodState state) {
List blocks = state.controlFlowGraph().preOrder();
for (Iterator i = blocks.iterator(); i.hasNext();)
((Block) i.next()).stackOptimizer().optimize();
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,306 @@
/*
* Class: ValueFolding
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import java.io.*;
import java.util.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.editor.EditorContext;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.ssa.ComponentVisitor;
import edu.purdue.cs.bloat.ssa.SSAGraph;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.Expr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiCatchStmt;
/**
* <tt>ValueFolding</tt> uses a <tt>ValueFolder</tt> to determine which
* nodes in an expression tree can be removed or replaced by common expression
* elimination and constant propagation.
*
* @see ValueFolder
*/
public class ValueFolding implements Optimization {
public static boolean DEBUG = false;
SideEffectChecker sideEffects;
ValueFolder folder;
boolean changed;
public static boolean DUMP = false;
public static boolean SAVEDUMP = false;
PrintWriter vn;
PrintWriter dump;
/**
* Performs value folding (common expression elimination and constant
* folding) on a control flow graph.
*/
int next = 1;
public void transform(MethodState state) {
FlowGraph cfg = state.controlFlowGraph();
if (DUMP) {
vn = new PrintWriter(System.out, true);
dump = new PrintWriter(System.out, true);
}
// MAY NOT BE THE BEST THING TO DO
// Repository context = cfg.method().declaringClass().context();
// Repository context = org.apache.bcel.Repository.getRepository();
// EditorContext context = new
// PersistentBloatContext(org.apache.bcel.Repository.getRepository());
// Get the context from the MethodState object. In theory, this may
// cause
// problems if PersistentBloatContext.closure starts meaning something,
// so you may have to return to the previous definition. But this way is
// much nicer.
EditorContext context = state.context();
sideEffects = new SideEffectChecker(context);
folder = new ValueFolder(true, context);
SSAGraph ssaGraph = new SSAGraph(cfg);
ssaGraph.visitComponents(new ComponentVisitor() {
public void visitComponent(List scc) {
// Maps Nodes in the SCC to their folded value
LinkedHashMap map = new LinkedHashMap(scc.size() * 2 + 1);
boolean changed = true;
while (changed) {
changed = false;
Iterator iter = scc.iterator();
int x = 0;
while (iter.hasNext()) {
Node node = (Node) iter.next();
if (DUMP) {
x++;
dump.println("Folding SCC Node " + node + " (" + x
+ " of " + scc.size() + ")");
}
if (fold(map, node)) {
changed = true;
}
}
if (DUMP)
dump.println("");
if (scc.size() == 1) {
break;
}
}
}
});
cfg.removeUnreachable();
folder = null;
sideEffects = null;
// Okay, we've successfully value folded, remove debugging files
}
/**
* Builds a mapping between the nodes in a CFG's SCCs and the expressions
* they are equivalent to.
*
* @param map
* A mapping between the SCCs of the CFG's SSA Graph
* (definitions) and the expressions they are folded to
* @param sscNode
* A Node in the SCC of the SSA Graph
*
* @return True, if the value in the mapping was changed.
*/
boolean fold(Map map, Node sccNode) {
Node node = (Node) map.get(sccNode);
if (DUMP)
dump
.println(" SCC Node " + sccNode + " is mapped to node "
+ node);
// The SCC node has not been folded yet, fold it to itself
if (node == null) {
node = sccNode;
}
if (!node.hasParent()) {
return false;
}
if (DEBUG) {
System.out.println("folding --- " + node + " in " + node.parent());
}
if (DUMP) {
dump.println(" Folding " + node + " (" + "VN="
+ node.valueNumber() + ") in " + node.parent());
}
int v = node.valueNumber();
if (v == -1) {
// Node has not been assigned a value number, can't do anything
return false;
}
folder.values.ensureSize(v + 1);
ConstantExpr oldValue = (ConstantExpr) folder.values.get(v);
ConstantExpr value = null;
if (DUMP)
dump.println(" Node " + node + " is mapped to constant "
+ oldValue);
if (node instanceof ConstantExpr) {
// If the node that we're dealing with is already a
// ConstantExpr, change it to the mapped value if it is
// different.
value = (ConstantExpr) node;
if (oldValue == null || !oldValue.equalsExpr(value)) {
// The node was not previously mapped to a constant, or it was
// mapped to a different constant. Update the mapping to
// relfect the new constant.
if (DEBUG) {
System.out.println("changed " + oldValue + " to " + value);
}
if (DUMP) {
dump.println(" Changed " + oldValue + " to " + value);
}
folder.values.set(v, value);
return true;
}
// Mapping was already correct, don't do anything.
return false;
}
if (node instanceof Expr && oldValue != null) {
// The node is a non-constant Expr that was mapped to a constant
if (node.parent() instanceof PhiCatchStmt) {
// Don't fold values inside PhiCatchStmts
return false;
}
sideEffects.reset();
node.visit(sideEffects);
if (!sideEffects.hasSideEffects()) {
// If the expression does not have side effects, then make a
// clone of the value to which it was mapped and map the clone
// to the original sccNode (which may or may not be node).
// Technically, the mapping did not change.
value = (ConstantExpr) oldValue.clone();
node.replaceWith(value);
map.put(sccNode, value);
return false;
}
}
if (value == null) {
// The node is mapped to nothing, Use the ValueFolder to
// determine a expression that node can be folded to.
folder.node = null;
node.visit(folder);
if (DEBUG) {
System.out.println("folded " + node + " to " + folder.node);
}
if (DUMP) {
dump.println(" Using ValueFolder to determine new value");
dump.println(" Folded " + node + " to " + folder.node);
}
if (folder.node != null) {
// Assert.isTrue(folder.node.hasParent(),
// "No parent for " + folder.node);
map.put(sccNode, folder.node);
}
if (folder.node instanceof ConstantExpr) {
// If the node was folded into a ConstantExpr, then fold it in
// the ValueFolder.
value = (ConstantExpr) folder.node;
folder.values.set(v, value);
return true;
}
}
return false;
}
public String traceMessage(String dateString) {
return " Value Folding: " + dateString;
}
public String preDebugMessage() {
return "--------Before Value Folding---------";
}
public String postDebugMessage() {
return "---------After Value Folding---------";
}
}

@ -0,0 +1,536 @@
/*
* Class: ValueNumbering
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import java.util.*;
import java.io.*;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.optimize.MethodState;
import edu.purdue.cs.bloat.optimize.Optimization;
import edu.purdue.cs.bloat.ssa.ComponentVisitor;
import edu.purdue.cs.bloat.ssa.SSAGraph;
import edu.purdue.cs.bloat.tree.ConstantExpr;
import edu.purdue.cs.bloat.tree.MemRefExpr;
import edu.purdue.cs.bloat.tree.Node;
import edu.purdue.cs.bloat.tree.PhiStmt;
import edu.purdue.cs.bloat.tree.Tree;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.util.Assert;
/**
* Performs value numbering analysis on the nodes in a control flow graph. Nodes
* with identical value numbers are folded into one another so that common
* (redundent) expressions are eliminated. Note that ValueNumbering works on the
* SSAGraph for the CFG and not the CFG itself.
*
* @see SSAGraph
*/
// L.T. Simpson 1996. Value-driven redundancy elimination. PhD
// Thesis. Rice University. Look it up. Chapter 4 contains the
// stuff on SCC-based value numbering.
public class ValueNumbering implements Optimization {
public static boolean DEBUG = false;
SSAGraph ssaGraph;
LinkedHashMap tuples; // Maps a Node to its Tuple
ValueFolder folder;
int next; // The next value number to assign
public String debugDirName = "debug";
public File debugDir;
public boolean DUMP = false;
private PrintWriter dump = new PrintWriter(System.out);
/**
* Performs value numbering on a control flow graph.
*
* @see ComponentVisitor
* @see SSAGraph
* @see ValueFolder
*/
public void transform(MethodState state) {
FlowGraph cfg = state.controlFlowGraph();
// Specify directory into which all debugging files should be
// placed
if (DUMP || ValueFolding.DUMP) {
String className = cfg.method().getClassName();
String methodName = cfg.method().getName();
String dirName = debugDirName + File.separator + className
+ File.separator + methodName;
debugDir = new File(dirName);
for (int nextDir = 1; debugDir.exists(); nextDir++) {
// Multiple directories
debugDir = new File(dirName + "_" + nextDir);
}
if (!debugDir.exists())
debugDir.mkdirs();
// General dumping file
try {
File dumpFile = new File(debugDir, "vn_dump");
dump = new PrintWriter(new FileWriter(dumpFile), true);
} catch (IOException ex) {
System.err.println(ex.toString());
}
}
ssaGraph = new SSAGraph(cfg);
tuples = new LinkedHashMap();
// Use state.context() to get the EditorContext. It breaks, go back to
// the
// "new PersistentBloatContext(...) version.
folder = new ValueFolder(false, state.context());
// new
// PersistentBloatContext(org.apache.bcel.Repository.getRepository()));
// cfg.method().declaringClass().context());
// AGAIN THIS MIGHT NOT BE THE BEST
next = 0;
final LinkedHashMap valid = new LinkedHashMap();
final LinkedHashMap optimistic = new LinkedHashMap();
ssaGraph.visitComponents(new ComponentVisitor() {
public void visitComponent(List scc) {
if (DEBUG || DUMP) {
dump.println("\nNumbering SCC = " + scc);
}
Iterator e = scc.iterator();
while (e.hasNext()) {
Node node = (Node) e.next();
node.setValueNumber(-1);
}
if (scc.size() > 1) {
if (DEBUG || DUMP) {
dump.println("Optimistic-----------------------");
}
boolean changed = true;
while (changed) {
changed = false;
Iterator iter = scc.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
if (valnum(node, optimistic)) {
changed = true;
}
}
}
}
if (DEBUG || DUMP) {
dump.println("Valid--------------------------------");
}
// The valid table contains the correct value numbers. Run
// through the each node in the SCC and call valnum.
// Presumably, the nodes are in reverse postorder.
Iterator iter = scc.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
valnum(node, valid);
}
}
});
if (DEBUG || DUMP) {
dump.println("Final value numbers--------------------------");
printValueNumbers(cfg, new PrintWriter(dump));
}
if (DUMP) {
System.out.println(" Dumping to: " + debugDir);
try {
File valueNumbers = new File(debugDir, "scc.txt");
ssaGraph
.printSCCs(new PrintWriter(new FileWriter(valueNumbers)));
} catch (IOException ex) {
System.err.println("IOException: " + ex);
}
}
ssaGraph = null;
tuples = null;
folder.cleanup();
folder = null;
// Make sure each node has a value number
cfg.visit(new TreeVisitor() {
public void visitTree(Tree tree) {
tree.visitChildren(this);
}
public void visitNode(Node node) {
node.visitChildren(this);
Assert.isTrue(node.valueNumber() != -1, "No value number for "
+ node);
}
});
}
private void printValueNumbers(FlowGraph cfg, final PrintWriter pw) {
cfg.visit(new TreeVisitor() {
public void visitTree(Tree tree) {
tree.visitChildren(this);
}
public void visitNode(Node node) {
node.visitChildren(this);
pw.println("VN[" + node + " " + System.identityHashCode(node) +
// " == " + ssaGraph.equivalent(node) + " " +
// System.identityHashCode(ssaGraph.equivalent(node)) +
"] = " + node.valueNumber());
}
});
}
/**
* Simplifies a node by examining its type. A ValueFolder may be used to
* perform simplification.
*
* @return The folded (simplified) value of the node (which may be the same
* as the node itself)
*/
private Node simplify(Node node) {
if (DEBUG || DUMP) {
dump.println("folding " + node + " in " + node.parent());
}
int v = node.valueNumber();
// A value number of -1 (i.e. value number has not yet been
// assigned) cannot be simplified.
if (v == -1) {
return node;
}
// A constant expression can't be simplified, set the value of
// value number v to be node
if (node instanceof ConstantExpr) {
folder.values.ensureSize(v + 1);
folder.values.set(v, node);
return node;
}
// Check for the value number in the folder.
if (v < folder.values.size()) {
ConstantExpr value = (ConstantExpr) folder.values.get(v);
if (value != null) {
return value;
}
}
// Else, use a ValueFolder to fold the node
folder.node = null;
node.visit(folder);
if (DEBUG || DUMP) {
dump.println("folded " + node + " to " + folder.node);
}
if (folder.node == null) {
// Nothing changed
return node;
}
// If we folded the node into a constant expression, add it to
// the values list
if (folder.node instanceof ConstantExpr) {
folder.values.ensureSize(v + 1);
folder.values.set(v, folder.node);
}
return folder.node;
}
/**
* Processes a Node in an SCC.
*/
private boolean valnum(Node node, LinkedHashMap table) {
boolean changed = false; // Did the table change?
Tuple tuple = (Tuple) tuples.get(node);
if (tuple == null) {
// Make a new Tuple for the node being processed
Node s = simplify(node);
tuple = new Tuple(s);
tuples.put(node, tuple);
if (DEBUG || DUMP) {
dump.println(" New tuple " + tuple);
}
} else if (DUMP) {
dump.println(" " + node + " mapped to tuple " + tuple);
}
Node w = (Node) table.get(tuple);
if (DEBUG || DUMP) {
dump.println(" Looking up " + tuple);
dump.println(" " + tuple + " mapped to node " + w
+ (w != null ? " (VN = " + w.valueNumber() + ")" : ""));
}
int value = -1;
if (w != null && w.valueNumber() != -1) {
value = w.valueNumber();
} else {
if (DEBUG || DUMP) {
dump.println(" New value number " + next);
}
value = next++;
}
Assert.isTrue(value != -1);
// Now make sure all equivalent nodes have the same value number.
Iterator iter = ssaGraph.equivalent(node).iterator();
while (iter.hasNext()) {
Node v = (Node) iter.next();
Tuple t = (Tuple) tuples.get(v);
if (t == null) {
// Will get done later.
continue;
}
if (v.valueNumber() != value) {
v.setValueNumber(value);
table.put(t, v);
if (DEBUG || DUMP) {
dump.println(" Assigning value number "
+ v.valueNumber() + " to " + v);
dump.println(" Mapping tuple " + t + " to node " + v);
}
changed = true;
}
}
return changed;
}
/**
* Tuple contains a Node and an associated hash value. The Node is the
* simplified version of another node. The main purpose of the Tuple class
* is to compare two Nodes to determine if they are the same with respect to
* their value numbers.
*/
class Tuple {
Node node;
int hash;
public Tuple(Node node) {
this.node = node;
List children = ssaGraph.children(node);
this.hash = NodeComparator.hashCode(node) + children.size();
}
public String toString() {
List children = ssaGraph.children(node);
String s = "<" + node + ", hash=" + hash;
Iterator iter = children.iterator();
while (iter.hasNext()) {
Node child = (Node) iter.next();
s += ", " + child + "{" + child.valueNumber() + "}";
}
s += ">";
return s;
}
public int hashCode() {
return hash;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Tuple) {
Tuple t = (Tuple) obj;
if (node == t.node) {
return true;
}
// All mem refs are unequal.
if (node instanceof MemRefExpr || t.node instanceof MemRefExpr) {
return false;
}
if (!NodeComparator.equals(node, t.node)) {
return false;
}
List children1 = ssaGraph.children(node);
List children2 = ssaGraph.children(t.node);
if (children1.size() != children2.size()) {
return false;
}
if (node instanceof PhiStmt) {
// The order of the children does not matter
int[] used = new int[next];
int free = 0; // The number of un-numbered children
Iterator iter = children1.iterator();
while (iter.hasNext()) {
Node child = (Node) iter.next();
int v = child.valueNumber();
if (v != -1) {
used[v]++;
} else {
free++;
}
}
iter = children2.iterator();
while (iter.hasNext()) {
Node child = (Node) iter.next();
int v = child.valueNumber();
if (v != -1) {
if (used[v] != 0) {
used[v]--;
} else {
free--;
}
} else {
free--;
}
}
if (free < 0) {
return false;
}
return true;
} else {
// The children of the nodes in the SSAGraph must have
// the
// same value numbers and be in the same order.
Iterator iter1 = children1.iterator();
Iterator iter2 = children2.iterator();
while (iter1.hasNext() && iter2.hasNext()) {
Node child1 = (Node) iter1.next();
Node child2 = (Node) iter2.next();
int v1 = child1.valueNumber();
int v2 = child2.valueNumber();
if (v1 != -1 && v2 != -1 && v1 != v2) {
return false;
}
}
if (iter1.hasNext() || iter2.hasNext()) {
// Size mismatch.
return false;
}
return true;
}
}
return false;
}
}
public String traceMessage(String dateString) {
return " Value Numbering: " + dateString;
}
public String preDebugMessage() {
return "--------Doing value numbering--------";
}
public String postDebugMessage() {
return null;
}
}

@ -0,0 +1,45 @@
<html>
<body>
<p>Performs transformations (optimizations) on a control flow graph.
There are several optimizations performed by classes in this package.
Older Java compilers produced poor code for initializing arrays.
BLOAT can replace this poor code with more efficient code by loading
the array from the constant pool. Dead code elimination removes code
from a method that does not contribute to the final output of the
program.</p>
<p>Value numbering associates a number with each expression such that
if two expressions have the same number, they have the same value. A
value folder is then used to eliminate redundent nodes from and to
propagate constants through the control flow graph.</p>
<p>Constant propagation removes unnecessary assignments by replacing
variables that are assigned constant values with those values. Copy
propagation removes unnecessary assignments to varibles to other
variables.</p>
<p>BLOAT was designed to optimize classes that were to be run inside a
persistent system that required special opcodes to perform operation
such as checking an object cache for a certain resident object. The
analysis that BLOAT does can eliminate some of these checks.</p>
<p>SSA-based partial redundency elimination (PRE) of expressions and
access paths can also be performed on a control flow graph. If a
calculation is redundent along one control flow path leading to a
merge point, PRE computes it once along <b>all</b> paths, assigns the
result to a variable, and replaces further occurrences of the
calculation with that variable. This way, the expression is only
computed once along any given control flow path.</p>
<p>Finally, peephole optimizations are performed on Java bytecode.
For instance, a push instruction followed by a pop instruction is
useless and can be removed. Additionally, unreachable code is removed
from the method.</p>
<p>This package also contains several auxiliary classes that perform
operations like determining whether or not an expression has side
effects and comparing two nodes.</p>
</body>
</html>

@ -0,0 +1,82 @@
/*
* Class: AddressStoreStmt
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import edu.purdue.cs.bloat.cfg.Subroutine;
/**
* Associated with an AddressStoreStmt is a Subroutine whose address (offset in
* the instruction sequence) is to be stored. Addresses may be loaded (using
* <i>astore</i>), but cannot be reloaded. Therefore, AddressStoreStmt is
* needed to differentiate between a regular (object reference) <i>astore</i>
* which is modeled by a LocalExpr.
*
* @see Tree#visit_astore
* @see Subroutine
* @see LocalExpr
*/
public class AddressStoreStmt extends Stmt {
final Subroutine sub;
/**
* Constructor.
*
* @param sub
*
*/
public AddressStoreStmt(Subroutine sub) {
this.sub = sub;
}
public Subroutine sub() {
return sub;
}
public void visitForceChildren(TreeVisitor visitor) {
}
public void visit(TreeVisitor visitor) {
visitor.visitAddressStoreStmt(this);
}
public Object clone() {
return copyInto(new AddressStoreStmt(sub));
}
}

@ -0,0 +1,146 @@
/*
* Class: ArithExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
/**
* ArithExpr represents a binary arithmetic expression. It consists of two
* operands and an operator.
*/
public class ArithExpr extends Expr {
final char operation; // Arithmetic operator
Expr left; // Expression on left-hand side of operation
Expr right; // Expression on right-hand side of operation
// Operators...
public static final char ADD = '+';
public static final char SUB = '-';
public static final char DIV = '/';
public static final char MUL = '*';
public static final char REM = '%';
public static final char AND = '&';
public static final char IOR = '|';
public static final char XOR = '^';
public static final char CMP = '?';
public static final char CMPL = '<';
public static final char CMPG = '>';
/**
* Constructor.
*
* @param operation
* Arithmetic operation that this expression performs.
* @param left
* Left-hand argument to operation.
* @param right
* Right-hand argument to operation.
* @param type
* The type of this expression.
*/
public ArithExpr(char operation, Expr left, Expr right, Type type) {
super(type);
this.operation = operation;
this.left = left;
this.right = right;
left.setParent(this);
right.setParent(this);
}
public int operation() {
return operation;
}
public Expr left() {
return left;
}
public Expr right() {
return right;
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
right.visit(visitor);
left.visit(visitor);
} else {
left.visit(visitor);
right.visit(visitor);
}
}
public void visit(TreeVisitor visitor) {
visitor.visitArithExpr(this);
}
public int exprHashCode() {
return 1 + operation ^ left.exprHashCode() ^ right.exprHashCode();
}
/**
* Compare this arithmetic expression to another Expression.
*
* @return True, if both expressions have the same contents.
*/
public boolean equalsExpr(Expr other) {
return other != null && other instanceof ArithExpr
&& ((ArithExpr) other).operation == operation
&& ((ArithExpr) other).left.equalsExpr(left)
&& ((ArithExpr) other).right.equalsExpr(right);
}
public Object clone() {
return copyInto(new ArithExpr(operation, (Expr) left.clone(),
(Expr) right.clone(), type));
}
}

@ -0,0 +1,95 @@
/*
* Class: ArrayLengthExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
import edu.purdue.cs.bloat.util.Assert;
/**
* <tt>ArrayLengthExpr</tt> represents the <i>arraylength</i> opcode which
* gets length of an array.
*/
public class ArrayLengthExpr extends Expr {
Expr array;
/**
* Constructor.
*
* @param array
* Array whose length is sought.
* @param type
* The type of this expression.
*/
public ArrayLengthExpr(Expr array, Type type) {
super(type);
this.array = array;
array.setParent(this);
}
public Expr array() {
return array;
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
array.visit(visitor);
} else {
array.visit(visitor);
}
}
public void visit(TreeVisitor visitor) {
visitor.visitArrayLengthExpr(this);
}
public int exprHashCode() {
return 3 + array.exprHashCode() ^ (int) Assert.simple(type).hashCode();
}
public boolean equalsExpr(Expr other) {
return other != null && other instanceof ArrayLengthExpr
&& ((ArrayLengthExpr) other).array.equalsExpr(array);
}
public Object clone() {
return copyInto(new ArrayLengthExpr((Expr) array.clone(), type));
}
}

@ -0,0 +1,116 @@
/*
* Class: ArrayRefExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
/**
* ArrayRefExpr represents an expression that references an element in an array.
*/
public class ArrayRefExpr extends MemRefExpr {
Expr array;
Expr index;
final Type elementType;
/**
* Constructor.
*
* @param array
* The array whose element we are indexing.
* @param index
* The index into the array.
* @param elementType
* The type of elements in array.
* @param type
* The type of this expression.
*/
public ArrayRefExpr(Expr array, Expr index, Type elementType, Type type) {
super(type);
this.array = array;
this.index = index;
this.elementType = elementType;
array.setParent(this);
index.setParent(this);
}
public Expr array() {
return array;
}
public Expr index() {
return index;
}
public Type elementType() {
return elementType;
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
index.visit(visitor);
array.visit(visitor);
} else {
array.visit(visitor);
index.visit(visitor);
}
}
public void visit(TreeVisitor visitor) {
visitor.visitArrayRefExpr(this);
}
public int exprHashCode() {
return 4 + array.exprHashCode() ^ index.exprHashCode();
}
public boolean equalsExpr(Expr other) {
return other != null && other instanceof ArrayRefExpr
&& ((ArrayRefExpr) other).array.equalsExpr(array)
&& ((ArrayRefExpr) other).index.equalsExpr(index);
}
public Object clone() {
return copyInto(new ArrayRefExpr((Expr) array.clone(), (Expr) index
.clone(), elementType, type));
}
}

@ -0,0 +1,454 @@
/*
* Class: AscendVisitor
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import java.util.*;
/**
* AscendVisitor is the superclass of Type0Visitor and Type1Visitor,
* conveniently containing the common code. It makes an upward traversal of the
* tree as if it were a binary tree (nodes with more than two children, such as
* a method call, are considered in a form similar to curried form).
*
* @author Thomas VanDrunen
*/
public abstract class AscendVisitor extends TreeVisitor {
HashMap defInfoMap; /* the same as the fields of Stack Optimizer */
HashMap useInfoMap; /* of the same name */
LocalExpr start; /* where we start the search from */
Node previous;
Vector visited;
public AscendVisitor(HashMap defInfoMap, HashMap useInfoMap) {
this.defInfoMap = defInfoMap;
this.useInfoMap = useInfoMap;
visited = new Vector();
}
abstract public void check(Node node);
public void visitTree(Tree tree) {
ListIterator iter = tree.stmts().listIterator(
tree.stmts().lastIndexOf(previous));
if (iter.hasPrevious()) {
Stmt p = (Stmt) iter.previous();
check(p);
}
/*
* Object prev = iter.previous(); if (prev instanceof LocalExpr)
* check(prev);
*/
}
public void visitExprStmt(ExprStmt stmt) {
previous = stmt;
stmt.parent().visit(this);
}
public void visitIfCmpStmt(IfCmpStmt stmt) {
if (stmt.right() == previous)
check(stmt.left());
else if (stmt.left() == previous) {
previous = stmt;
stmt.parent().visit(this);
}
}
public void visitIfZeroStmt(IfZeroStmt stmt) {
previous = stmt;
stmt.parent.visit(this);
}
public void visitInitStmt(InitStmt stmt) {
LocalExpr[] targets = stmt.targets();
for (int i = 0; i < targets.length; i++)
if (targets[i] == previous)
if (i > 0)
check(targets[i - 1]);
else
break;
}
public void visitGotoStmt(GotoStmt stmt) {
}
public void visitLabelStmt(LabelStmt stmt) {
}
public void visitMonitorStmt(MonitorStmt stmt) {
previous = stmt;
stmt.parent().visit(this);
}
public void visitPhiStmt(PhiStmt stmt) {
if (stmt instanceof PhiCatchStmt)
visitPhiCatchStmt((PhiCatchStmt) stmt);
else if (stmt instanceof PhiJoinStmt)
visitPhiJoinStmt((PhiJoinStmt) stmt);
/*
* else if (stmt instanceof PhiReturnStmt)
* visitPhiReturnStmt((PhiReturnStmt) stmt);
*/
}
public void visitCatchExpr(CatchExpr expr) {
}
public void visitDefExpr(DefExpr expr) {
if (expr instanceof MemExpr)
visitMemExpr((MemExpr) expr);
}
public void visitStackManipStmt(StackManipStmt stmt) {
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
}
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
}
public void visitRetStmt(RetStmt stmt) {
}
public void visitReturnExprStmt(ReturnExprStmt stmt) {
previous = stmt;
stmt.parent.visit(this);
}
public void visitReturnStmt(ReturnStmt stmt) {
}
public void visitAddressStoreStmt(AddressStoreStmt stmt) {
}
public void visitStoreExpr(StoreExpr expr) {
if (expr.target() instanceof LocalExpr
|| expr.target() instanceof StaticFieldExpr) {
if (previous == expr.expr()) { // can't be target, because then
// it would be a definition, for which
// Type0Visitor is not called
previous = expr;
expr.parent.visit(this);
}
}
else if (expr.target() instanceof ArrayRefExpr) {
if (previous == expr.expr())
check(((ArrayRefExpr) expr.target()).index());
else if (previous == expr.target()) {
previous = expr;
expr.parent.visit(this);
}
}
else if (expr.target() instanceof FieldExpr) {
if (previous == expr.expr())
check(expr.target());
else if (previous == expr.target()) {
previous = expr;
expr.parent.visit(this);
}
}
}
public void visitJsrStmt(JsrStmt stmt) {
}
public void visitSwitchStmt(SwitchStmt stmt) {
if (previous == stmt.index()) {
previous = stmt;
stmt.parent.visit(this);
}
}
public void visitThrowStmt(ThrowStmt stmt) {
}
public void visitStmt(Stmt stmt) {
}
public void visitSCStmt(SCStmt stmt) {
}
public void visitSRStmt(SRStmt stmt) {
}
public void visitArithExpr(ArithExpr expr) {
if (previous == expr.left()) {
previous = expr;
expr.parent.visit(this);
} else if (previous == expr.right())
check(expr.left());
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
}
public void visitMemExpr(MemExpr expr) {
if (expr instanceof MemRefExpr)
visitMemRefExpr((MemRefExpr) expr);
else if (expr instanceof VarExpr)
visitVarExpr((VarExpr) expr);
}
public void visitMemRefExpr(MemRefExpr expr) {
if (expr instanceof FieldExpr)
visitFieldExpr((FieldExpr) expr);
else if (expr instanceof StaticFieldExpr)
visitStaticFieldExpr((StaticFieldExpr) expr);
else if (expr instanceof ArrayRefExpr)
visitArrayRefExpr((ArrayRefExpr) expr);
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
if (previous == expr.array()) { // the array reference is like the
previous = expr; // left child
expr.parent().visit(this);
} else if (previous == expr.index()) // the index is like the
check(expr.array()); // right child
}
public void visitCallExpr(CallExpr expr) {
if (expr instanceof CallMethodExpr)
visitCallMethodExpr((CallMethodExpr) expr);
if (expr instanceof CallStaticExpr)
visitCallStaticExpr((CallStaticExpr) expr);
}
public void visitCallMethodExpr(CallMethodExpr expr) {
if (previous == expr.receiver()) {
previous = expr;
expr.parent.visit(this);
}
else {
Expr[] params = expr.params();
for (int i = 0; i < params.length; i++)
if (params[i] == previous)
if (i > 0)
check(params[i - 1]);
else
check(expr.receiver());
}
}
public void visitCallStaticExpr(CallStaticExpr expr) {
Expr[] params = expr.params();
for (int i = 0; i < params.length; i++)
if (params[i] == previous) {
if (i > 0)
check(params[i - 1]);
else {
previous = expr;
expr.parent().visit(this);
}
break;
}
}
public void visitCastExpr(CastExpr expr) {
previous = expr;
expr.parent.visit(this);
}
public void visitConstantExpr(ConstantExpr expr) {
}
public void visitFieldExpr(FieldExpr expr) {
if (previous == expr.object()) {
previous = expr;
expr.parent.visit(this);
}
}
public void visitInstanceOfExpr(InstanceOfExpr expr) {
if (previous == expr.expr()) {
previous = expr;
expr.parent.visit(this);
}
}
public void visitLocalExpr(LocalExpr expr) {
}
public void visitNegExpr(NegExpr expr) {
if (previous == expr.expr()) {
previous = expr;
expr.parent.visit(this);
}
}
public void visitNewArrayExpr(NewArrayExpr expr) {
if (previous == expr.size()) {
previous = expr;
expr.parent.visit(this);
}
}
public void visitNewExpr(NewExpr expr) {
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
Expr[] dims = expr.dimensions;
for (int i = 0; i < dims.length; i++)
if (dims[i] == previous)
if (i > 0)
check(dims[i - 1]);
else {
previous = expr;
expr.parent().visit(this);
}
}
public void visitCheckExpr(CheckExpr expr) {
if (expr instanceof ZeroCheckExpr)
visitZeroCheckExpr((ZeroCheckExpr) expr);
else if (expr instanceof RCExpr)
visitRCExpr((RCExpr) expr);
else if (expr instanceof UCExpr)
visitUCExpr((UCExpr) expr);
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
/*
* if (previous == expr.expr()) { previous = expr;
* expr.parent.visit(this); }
*/
}
public void visitRCExpr(RCExpr expr) {
}
public void visitUCExpr(UCExpr expr) {
}
public void visitReturnAddressExpr(ReturnAddressExpr expr) {
}
public void visitShiftExpr(ShiftExpr expr) {
if (previous == expr.expr()) { // the expression to be shifted is like
previous = expr; // the left child
expr.parent().visit(this);
} else if (previous == expr.bits()) // the bits shifted is like
check(expr.expr()); // the right child
}
public void visitStackExpr(StackExpr expr) {
}
public void visitVarExpr(VarExpr expr) {
if (expr instanceof LocalExpr)
visitLocalExpr((LocalExpr) expr);
if (expr instanceof StackExpr)
visitStackExpr((StackExpr) expr);
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
}
public void visitExpr(Expr expr) {
}
public void visitNode(Node node) {
}
}

@ -0,0 +1,56 @@
/*
* Class: Assign
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
/**
* Classes that implement Assign involve an assignment (definition).
*
* @see InitStmt
* @see PhiStmt
* @see StackManipStmt
* @see StoreExpr
*/
public interface Assign {
/**
* Returns the expressions that may be modified (defined) by this expression
* or statement.
*/
public abstract DefExpr[] defs();
}

@ -0,0 +1,89 @@
/*
* Class: CallExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import edu.purdue.cs.bloat.editor.MethodRef;
/**
* <tt>CallExpr</tt> is a superclass of expressions that represent the
* invocation of a method. It consists of an array of <tt>Expr</tt> that
* represent the arguments to a method and a <tt>MethodRef</tt> that
* represents the method itself.
*
* @see CallMethodExpr
* @see CallStaticExpr
*/
public abstract class CallExpr extends Expr {
final Expr[] params; // The parameters to the method
final MethodRef method; // The method to be invoked
public int voltaPos; // used for placing swaps and stuff
/**
* Constructor.
*
* @param params
* Parameters to the method. Note that these parameters do not
* contain parameter 0, the "this" pointer.
* @param method
* The method that is to be invoked.
* @param type
* The type of this expression (i.e. the return type of the
* method being called).
*/
public CallExpr(Expr[] params, MethodRef method) {
super(method.type());
this.params = params;
this.method = method;
for (int i = 0; i < params.length; i++) {
params[i].setParent(this);
}
}
public MethodRef method() {
return method;
}
public Expr[] params() {
return params;
}
}

@ -0,0 +1,141 @@
/*
* Class: CallMethodExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import edu.purdue.cs.bloat.editor.MethodRef;
/**
* CallMethodExpr represents the invocation of an object's method. In addition
* to knowing what method is being called and its parameters, it also knows what
* "kind" of method call it is (<tt>VIRTUAL</tt>, <tt>NONVIRTUAL</tt>, or
* <tt>INTERFACE</tt>) and the object that is the reciever of this method
* call.
*
* @see CallStaticExpr
*/
public class CallMethodExpr extends CallExpr {
// Different kinds of methods to call...
public static final int VIRTUAL = 0; // invokevirtual
public static final int NONVIRTUAL = 1; // invokespecial
public static final int INTERFACE = 2; // invokeinterface
Expr receiver;
final int kind;
/**
* Constructor.
*
* @param kind
* The kind (VIRTUAL, NONVIRTUAL, or INTERFACE) of method that is
* being called.
* @param receiver
* The expression (object) whose method is being called.
* @param params
* Parameters to the method.
* @param method
* The method being called.
* @param type
* The type of this expression.
*/
public CallMethodExpr(int kind, Expr receiver, Expr[] params,
MethodRef method) {
super(params, method);
this.receiver = receiver;
this.kind = kind;
receiver.setParent(this);
}
public int kind() {
return kind;
}
public Expr receiver() {
return receiver;
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
for (int i = params.length - 1; i >= 0; i--) {
params[i].visit(visitor);
}
receiver.visit(visitor);
} else {
receiver.visit(visitor);
for (int i = 0; i < params.length; i++) {
params[i].visit(visitor);
}
}
}
public void visit(TreeVisitor visitor) {
visitor.visitCallMethodExpr(this);
}
public int exprHashCode() {
int v = 5 + kind ^ receiver.exprHashCode();
for (int i = 0; i < params.length; i++) {
v ^= params[i].exprHashCode();
}
return v;
}
public boolean equalsExpr(Expr other) {
return false;
}
public Object clone() {
Expr[] p = new Expr[params.length];
for (int i = 0; i < params.length; i++) {
p[i] = (Expr) params[i].clone();
}
return copyInto(new CallMethodExpr(kind, (Expr) receiver.clone(), p,
method));
}
}

@ -0,0 +1,106 @@
/*
* Class: CallStaticExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import edu.purdue.cs.bloat.editor.MethodRef;
/**
* CallStaticExpr represents the <tt>invokestatic</tt> opcode which invokes a
* class (static) method. Static methods can always be inlined.
*
* @see CallMethodExpr
*/
public class CallStaticExpr extends CallExpr {
// invokestatic
/**
* Constructor.
*
* @param params
* Parameters to the method.
* @param method
* The (class) method to be invoked.
* @param type
* The type of this expression.
*/
public CallStaticExpr(Expr[] params, MethodRef method) {
super(params, method);
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
for (int i = params.length - 1; i >= 0; i--) {
params[i].visit(visitor);
}
} else {
for (int i = 0; i < params.length; i++) {
params[i].visit(visitor);
}
}
}
public void visit(TreeVisitor visitor) {
visitor.visitCallStaticExpr(this);
}
public int exprHashCode() {
int v = 6;
for (int i = 0; i < params.length; i++) {
v ^= params[i].exprHashCode();
}
return v;
}
public boolean equalsExpr(Expr other) {
return false;
}
public Object clone() {
Expr[] p = new Expr[params.length];
for (int i = 0; i < params.length; i++) {
p[i] = (Expr) params[i].clone();
}
return copyInto(new CallStaticExpr(p, method));
}
}

@ -0,0 +1,116 @@
/*
* Class: CastExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
/**
* CastExpr represents an expression that casts an object to a given type.
*/
public class CastExpr extends Expr {
Expr expr; // An expression (object) to cast
final Type castType; // The Type to cast expr to
/**
* Constructor.
*
* @param expr
* Expression (object) to be cast.
* @param type
* The type to which to cast expr and as well as the type of this
* expression.
*/
public CastExpr(Expr expr, Type type) {
this(expr, type, type);
}
/**
* Constructor.
*
* @param expr
* Expression (object) to be cast.
* @param castType
* The type to which to cast expr.
* @param type
* The type of this expression.
*/
public CastExpr(Expr expr, Type castType, Type type) {
super(type);
this.expr = expr;
this.castType = castType;
expr.setParent(this);
}
public Expr expr() {
return expr;
}
public Type castType() {
return castType;
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
expr.visit(visitor);
} else {
expr.visit(visitor);
}
}
public void visit(TreeVisitor visitor) {
visitor.visitCastExpr(this);
}
public int exprHashCode() {
return 7 + expr.exprHashCode();
}
public boolean equalsExpr(Expr other) {
return other != null && other instanceof CastExpr
&& ((CastExpr) other).castType.equals(castType)
&& ((CastExpr) other).expr.equalsExpr(expr);
}
public Object clone() {
return copyInto(new CastExpr((Expr) expr.clone(), castType, type));
}
}

@ -0,0 +1,104 @@
/*
* Class: CatchExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
import edu.purdue.cs.bloat.cfg.FlowGraph;
import edu.purdue.cs.bloat.util.Assert;
/**
* CatchExpr represents an expression that catches an exception. A CatchExpr is
* used when evaluating a method's try-catch blocks when a control flow graph is
* constructed.
*
* @see TryCatch
* @see FlowGraph#FlowGraph
* @see MethodEditor
*/
public class CatchExpr extends Expr {
final Type catchType;
/**
* Constructor.
*
* @param catchType
* The type of the exception that is being caught.
* @param type
* The type of this expression.
*/
public CatchExpr(Type catchType, Type type) {
super(type);
this.catchType = catchType;
}
public void visitForceChildren(TreeVisitor visitor) {
}
public void visit(TreeVisitor visitor) {
visitor.visitCatchExpr(this);
}
public Type catchType() {
return catchType;
}
public int exprHashCode() {
return 8 + (int) Assert.simple(type).hashCode() ^ catchType.hashCode();
}
public boolean equalsExpr(Expr other) {
if (other instanceof CatchExpr) {
CatchExpr c = (CatchExpr) other;
if (catchType != null) {
return catchType.equals(c.catchType);
} else {
return c.catchType == null;
}
}
return false;
}
public Object clone() {
return copyInto(new CatchExpr(catchType, type));
}
}

@ -0,0 +1,96 @@
/*
* Class: CheckExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
import edu.purdue.cs.bloat.util.Assert;
/**
* CheckExpr is a superclass for classes representing a check on an expression.
* For instance, a CheckExpr is inserted into the tree before the divisor of a
* divide operation. The CheckExpr checks to make sure that the divisor is not
* zero.
*
* @see RCExpr
* @see UCExpr
* @see ZeroCheckExpr
*/
public abstract class CheckExpr extends Expr {
Expr expr;
/**
* Constructor.
*
* @param expr
* An expression that is to be checked.
* @param type
* The type of this expression.
*/
public CheckExpr(Expr expr, Type type) {
super(type);
this.expr = expr;
expr.setParent(this);
}
public void visitForceChildren(TreeVisitor visitor) {
if (visitor.reverse()) {
expr.visit(visitor);
} else {
expr.visit(visitor);
}
}
/**
* Returns the expression being checked.
*/
public Expr expr() {
return expr;
}
public int exprHashCode() {
return 9 + expr.exprHashCode() ^ (int) Assert.simple(type).hashCode();
}
public boolean equalsExpr(Expr other) {
return other != null && other instanceof CheckExpr
&& ((CheckExpr) other).expr.equalsExpr(expr);
}
}

@ -0,0 +1,60 @@
/*
* Class: CondExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
/**
* CondExpr is a superclass for conditional expressions. That is, an expression
* that yields a true or false value.
*
* @see InstanceOfExpr
*/
public abstract class CondExpr extends Expr {
/**
* Constructor.
*
* @param type
* The Type of this expression.
*/
public CondExpr(Type type) {
super(type);
}
}

@ -0,0 +1,127 @@
/*
* Class: ConstantExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
/**
* ConstantExpr represents a constant expression. It is used when opcodes <i>ldc</i>,
* <i>iinc</i>, and <i>getstatic</i> are visited. It value must be an Integer,
* Long, Float, Double, or String.
*/
public class ConstantExpr extends Expr implements LeafExpr {
// ldc
final Object value; // The operand to the ldc instruction
/**
* Constructor.
*
* @param value
* The operand of the ldc instruction
* @param type
* The Type of the operand
*/
public ConstantExpr(Object value, Type type) {
super(type);
this.value = value;
/*
* Assert.isTrue(((value == null)||(value instanceof Integer)||(value
* instanceof Long)|| (value instanceof Float)||(value instanceof
* Double)|| (value instanceof String)||(value instanceof Byte)|| (value
* instanceof Short)||(value instanceof Boolean)), "Illegal ConstantExpr
* value:" + value);
*/
}
/**
* @return The operand of the ldc instruction
*/
public Object value() {
return value;
}
public void visitForceChildren(TreeVisitor visitor) {
}
public void visit(TreeVisitor visitor) {
visitor.visitConstantExpr(this);
}
/**
* @return A hash code for this expression.
*/
public int exprHashCode() {
if (value != null) {
return 10 + value.hashCode();
}
return 10;
}
/**
* Compare this ConstantExpr to another Expr.
*
* @param other
* An Expr to compare this to.
*
* @return True, if this and other are the same (that is, have the same
* contents).
*/
public boolean equalsExpr(Expr other) {
if (!(other instanceof ConstantExpr)) {
return false;
}
if (value == null) {
return ((ConstantExpr) other).value == null;
}
if (((ConstantExpr) other).value == null) {
return false;
}
return ((ConstantExpr) other).value.equals(value);
}
public Object clone() {
return copyInto(new ConstantExpr(value, type));
}
}

@ -0,0 +1,136 @@
/*
* Class: DefExpr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import java.util.*;
import org.apache.bcel.generic.Type;
/**
* An expression in which a definition occurs. Each instance has a unique
* version number associated with it.
*/
public abstract class DefExpr extends Expr {
Set uses; // Expressions in which the definition is used
int version; // Which number DefExpr is this?
static int next = 0; // Total number of DefExprs
/**
* Constructor.
*
* @param type
* The Type (descriptor) of this expression
*/
public DefExpr(Type type) {
super(type);
uses = new LinkedHashSet();
version = next++;
}
/**
* Clean up this expression. Notify all the expressions that use this
* definition that it is no longer their defining expression.
*/
public void cleanupOnly() {
super.cleanupOnly();
List a = new ArrayList(uses);
uses.clear();
Iterator e = a.iterator();
while (e.hasNext()) {
Expr use = (Expr) e.next();
use.setDef(null);
}
}
/**
* Returns Number DefExpr this is. This is also the SSA version number of
* the expression that this <tt>DefExpr</tt> defines.
*/
public int version() {
return version;
}
/**
* Determines whether or not this <tt>DefExpr</tt> defines a local
* variable in its parent.
*
* @see Assign#defs
*/
public boolean isDef() {
if (parent instanceof Assign) {
DefExpr[] defs = ((Assign) parent).defs();
if (defs != null) {
for (int i = 0; i < defs.length; i++) {
if (defs[i] == this) {
return true;
}
}
}
}
return false;
}
/**
* Returns the <tt>Expr</tt>s in which the variable defined by this are
* used.
*/
public Collection uses() {
return new LinkedHashSet(uses);
}
public boolean hasUse(Expr use) {
return uses.contains(use);
}
protected void addUse(Expr use) {
uses.add(use);
}
protected void removeUse(Expr use) {
uses.remove(use);
}
}

@ -0,0 +1,60 @@
/*
* Class: DefInformation
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
/**
* DefInformation contains information about the definition of a local variable
*
* @author Thomas VanDrunen
*/
public class DefInformation {
int type1s;
int uses;
int usesFound;
public DefInformation(int uses) {
type1s = 0;
this.uses = uses;
usesFound = 0;
}
}

@ -0,0 +1,452 @@
/*
* Class: DescendVisitor
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import java.util.*;
/**
* DecsendVisitor is the superclass of a few private classes of Type0Visitor and
* Type1Visitor. It descends the tree, keeping track of the number of right
* links that have been taken.
*/
public abstract class DescendVisitor extends TreeVisitor {
HashMap useInfoMap;
HashMap defInfoMap;
boolean found;
Node beginNode; // where this visitor starts its search from
LocalExpr start; // where the original search began
int exchangeFactor;
public DescendVisitor(HashMap useInfoMap, HashMap defInfoMap) {
this.useInfoMap = useInfoMap;
this.defInfoMap = defInfoMap;
}
public boolean search(Node beginNode, LocalExpr start) {
this.beginNode = beginNode;
this.start = start;
exchangeFactor = 0;
found = false;
beginNode.visit(this);
return found;
}
public void visitExprStmt(ExprStmt stmt) {
stmt.expr().visit(this);
}
public void visitIfStmt(IfStmt stmt) {
if (stmt instanceof IfCmpStmt)
visitIfCmpStmt((IfCmpStmt) stmt);
else if (stmt instanceof IfZeroStmt)
visitIfZeroStmt((IfZeroStmt) stmt);
}
public void visitIfCmpStmt(IfCmpStmt stmt) {
stmt.left().visit(this); // search the left branch
if (!found) { // if nothing has been found
exchangeFactor++; // increase the exchange factor,
if (stmt.left().type().getSize() == 2)
exchangeFactor++; // twice to get
// around wides
if (exchangeFactor < 3)
stmt.right().visit(this); // search the right branch.
}
}
public void visitIfZeroStmt(IfZeroStmt stmt) {
stmt.expr().visit(this);
}
public void visitInitStmt(InitStmt stmt) {
// would have been checked by the Type0Visitor
}
public void visitGotoStmt(GotoStmt stmt) {
}
public void visitLabelStmt(LabelStmt stmt) {
}
public void visitMonitorStmt(MonitorStmt stmt) {
}
public void visitPhiStmt(PhiStmt stmt) {
if (stmt instanceof PhiCatchStmt)
visitPhiCatchStmt((PhiCatchStmt) stmt);
else if (stmt instanceof PhiJoinStmt)
visitPhiJoinStmt((PhiJoinStmt) stmt);
/*
* else if (stmt instanceof PhiReturnStmt)
* visitPhiReturnStmt((PhiReturnStmt) stmt);
*/
}
public void visitCatchExpr(CatchExpr expr) {
}
public void visitDefExpr(DefExpr expr) {
if (expr instanceof MemExpr)
visitMemExpr((MemExpr) expr);
}
public void visitStackManipStmt(StackManipStmt stmt) {
}
public void visitPhiCatchStmt(PhiCatchStmt stmt) {
}
public void visitPhiJoinStmt(PhiJoinStmt stmt) {
}
public void visitRetStmt(RetStmt stmt) {
}
public void visitReturnExprStmt(ReturnExprStmt stmt) {
}
public void visitReturnStmt(ReturnStmt stmt) {
}
public void visitAddressStoreStmt(AddressStoreStmt stmt) {
}
// StoreExprs are very difficult because they represent several
// types of expressions. What we do will depend on what the target
// of the store is: ArrayRefExpr, FieldExpr, StaticFieldExpr,
// or LocalExpr
public void visitStoreExpr(StoreExpr expr) {
MemExpr target = expr.target();
if (target instanceof ArrayRefExpr) {
// ArrayRefExpr: the store will be something like an astore
// which manipulates the stack like
// arrayref, index, val => ...
// so, think of the tree like
// (StoreExpr)
// / \
// Array Ref .
// / \
// index value
// This is unlike the structure of the tree BLOAT uses for
// intermediate representation, but it better relates to what's
// on the stack at what time
((ArrayRefExpr) target).array().visit(this); // visit the
// left child
if (!found) { // if match wasn't found
exchangeFactor++; // take the right branch
if (exchangeFactor < 3) { // (an array ref isn't wide)
// visit next left child
((ArrayRefExpr) target).index().visit(this);
if (!found) { // if match wasn't found
exchangeFactor++;
if (exchangeFactor < 3) // (an index isn't wide)
expr.expr().visit(this); // search the right
// branch
} // end seaching RR
}
} // end searching R
} // end case where target is ArrayRefExpr
else if (target instanceof FieldExpr) {
// FieldExpr: the store will be like a putfield
// which manipulates the stack like
// objref, val => ...
// so, think of the tree like
// (StoreExpr)
// / \
// Object Ref value
((FieldExpr) target).object().visit(this); // visit the left child
if (!found) {
exchangeFactor++; // (an object ref isn't wide)
if (exchangeFactor < 3) {
expr.expr().visit(this);
}
}
} // end case where target is FieldRef
else if (target instanceof StaticFieldExpr) {
// StaticFieldExpr: the store will be like a putstatic
// which manipulates the stack like
// val => ...
// so, think of the tree like
// (StoreExpr)
// /
// value
expr.expr.visit(this);
}
else if (target instanceof LocalExpr) {
// LocalExpr: the store will be like istore/astore/etc.
// which manipulates the stack like
// val => ...
// so, think of the tree like
// (StoreExpr)
// /
// value
expr.expr.visit(this);
}
}
public void visitJsrStmt(JsrStmt stmt) {
}
public void visitSwitchStmt(SwitchStmt stmt) {
}
public void visitThrowStmt(ThrowStmt stmt) {
}
public void visitStmt(Stmt stmt) {
}
public void visitSCStmt(SCStmt stmt) {
}
public void visitSRStmt(SRStmt stmt) {
}
public void visitArithExpr(ArithExpr expr) { // important one
expr.left().visit(this); // visit the left branch
if (!found) { // if a match isn't found yet
exchangeFactor++; // increase the exchange factor
if (expr.left().type().getSize() == 2)
exchangeFactor++;
// twice if wide
if (exchangeFactor < 3) {
expr.right().visit(this); // visit right branch
}
}
}
public void visitArrayLengthExpr(ArrayLengthExpr expr) {
expr.array().visit(this);
}
public void visitMemExpr(MemExpr expr) {
if (expr instanceof LocalExpr)
visitLocalExpr((LocalExpr) expr);
}
public void visitMemRefExpr(MemRefExpr expr) {
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
}
public void visitCallExpr(CallExpr expr) {
if (expr instanceof CallMethodExpr)
visitCallMethodExpr((CallMethodExpr) expr);
else if (expr instanceof CallStaticExpr)
visitCallStaticExpr((CallStaticExpr) expr);
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Method invocations are to be thought of, in terms of
// binary expression trees, as
// (CallMethodExpr)
// / \
// receiver .
// / \
// arg1 .
// / \
// arg2 .
// / \
// arg3 ...
// This might be the opposite of what one would think in terms
// of currying (ie, one might think of currying in terms of
// left associativity), but this gives a better picture of what
// happens to the stack when invokestatic or invokevirtual is called:
// objectref, [arg1, [arg2 ...]] => ...
expr.receiver().visit(this);
Expr[] params = expr.params();
if (!found && exchangeFactor < 2 && params.length > 0) {
exchangeFactor++; // (reciever won't be wide)
params[0].visit(this);
}
}
public void visitCallStaticExpr(CallStaticExpr expr) {
Expr[] params = expr.params();
if (params.length > 0)
params[0].visit(this);
if (!found && exchangeFactor < 2 && params.length > 1) {
exchangeFactor++;
params[1].visit(this);
}
}
public void visitCastExpr(CastExpr expr) {
expr.expr().visit(this);
}
public void visitConstantExpr(ConstantExpr expr) {
}
public void visitFieldExpr(FieldExpr expr) {
expr.object.visit(this);
}
public void visitInstanceOfExpr(InstanceOfExpr expr) {
expr.expr().visit(this);
}
/* needs to be different for Type0 and Type1 */
public abstract void visitLocalExpr(LocalExpr expr);
public void visitNegExpr(NegExpr expr) {
expr.expr().visit(this);
}
public void visitNewArrayExpr(NewArrayExpr expr) {
expr.size().visit(this);
}
public void visitNewExpr(NewExpr expr) {
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
// Think of the tree like
// (NewMultiArrayExpr)
// / \
// count1 .
// / \
// count2 etc.
// since multianewarray manipulates the stack like
// count1, [count1 ...] => ...
Expr[] dims = expr.dimensions();
if (dims.length > 0)
dims[0].visit(this);
if (!found && exchangeFactor < 2 && dims.length > 1) {
exchangeFactor++; // (count1 won't be wide)
dims[1].visit(this);
}
}
public void visitCheckExpr(CheckExpr expr) {
if (expr instanceof ZeroCheckExpr)
visitZeroCheckExpr((ZeroCheckExpr) expr);
else if (expr instanceof RCExpr)
visitRCExpr((RCExpr) expr);
else if (expr instanceof UCExpr)
visitUCExpr((UCExpr) expr);
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
// perhaps add something here
}
public void visitRCExpr(RCExpr expr) {
}
public void visitUCExpr(UCExpr expr) {
}
public void visitReturnAddressExpr(ReturnAddressExpr expr) {
}
public void visitShiftExpr(ShiftExpr expr) {
}
public void visitVarExpr(VarExpr expr) {
if (expr instanceof LocalExpr)
visitLocalExpr((LocalExpr) expr);
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
}
public void visitExpr(Expr expr) {
}
}

@ -0,0 +1,65 @@
/*
* Class: EliminationInformation
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author John N Zigman
* @author Arrin Daley
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import java.util.*;
public class EliminationInformation {
public Vector Occurences;
public int type1s;
public int uniqueNumber;
static int nextUN = 0;
public EliminationInformation() {
uniqueNumber = nextUN;
nextUN++;
Occurences = new Vector();
type1s = 0;
}
public String toString() {
return uniqueNumber + "+" + type1s + Occurences.toString();
}
}

@ -0,0 +1,246 @@
/*
* Class: Expr
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
import org.apache.bcel.generic.Type;
import edu.purdue.cs.bloat.util.Assert;
/**
* Expr is the superclass for a number of other classes representing expressions
* in byte code. Expressions are typed and may be nested.
*
* @see DefExpr
*/
public abstract class Expr extends Node implements Cloneable {
protected Type type; // The type (descriptor) of this expression
private DefExpr def; // The expression in which this expression
// is defined (if applicable)
private Object comparator;
/**
* Constructor. Initializes an expression with a given type.
*
* @param type
* The initial Type (descriptor) of this expression.
*/
public Expr(Type type) {
this.def = null;
this.comparator = new ExprComparator();
this.type = type;
}
/**
* Sets the type of this expression. Returns whether or not the type changed
* as a result of calling this method.
*/
public boolean setType(Type type) {
if (!this.type.equals(type)) {
// Assert.isTrue((type.equals(Type.OBJECT) ||
// type.equals(Type.INT) ||
// type.equals(Type.LONG) || type.equals(Type.FLOAT) ||
// type.equals(Type.DOUBLE) || type.equals(Type.STRING) ||
// type.equals(Type.BYTE) || type.equals(Type.SHORT) ||
// type.equals(Type.BOOLEAN)),
// "Illegal ConstantExpr type:" + type);
// if (Tree.DEBUG) {
// System.out.println(" setting typeof(" + this + ") = " +
// type);
// }
this.type = type;
return true;
}
return false;
}
/**
* Returns whether or not this expression is a defining occurrence. By
* default, false is returned.
*/
public boolean isDef() {
return false;
}
/**
* Returns the statement to which this expression belongs. It essentially
* searches up the expression tree for this expression's first ancestor
* which is a Stmt.
*/
public Stmt stmt() {
Node p = parent;
while (!(p instanceof Stmt)) {
Assert.isTrue(!(p instanceof Tree), "Invalid ancestor of " + this);
Assert.isTrue(p != null, "Null ancestor of " + this);
p = p.parent;
}
return (Stmt) p;
}
/**
* Returns the Type of this expression.
*/
public Type type() {
return type;
}
/**
* Cleans up this expression only, not its children.
*/
public void cleanupOnly() {
setDef(null);
}
/**
* Sets the expression that defines this expression.
*
* @param def
* Defining expression.
*/
public void setDef(DefExpr def) {
// if (Tree.DEBUG) {
// System.out.println(" setting def of " + this +
// " (" + System.identityHashCode(this) + ") to " + def);
// }
if (this.def == def) {
return;
}
// If this Expr already had a defining statement, remove this from the
// DefExpr use list.
if (this.def != null) {
this.def.removeUse(this);
}
if (this.isDef()) {
Assert.isTrue(def == this || def == null);
this.def = null;
return;
}
this.def = def;
if (this.def != null) {
this.def.addUse(this); // This Expr is a use of def
}
}
/**
* Returns the expression in which this Expr is defined.
*/
public DefExpr def() {
return def;
}
/**
* Returns the hash code for this expresion.
*/
public abstract int exprHashCode();
/**
* Compares this expression to another.
*
* @param other
* Expr to which to compare this.
*/
public abstract boolean equalsExpr(Expr other);
public abstract Object clone();
/**
* Copies the contents of another expression in this one.
*
* @param expr
* The expression from which to copy.
*/
protected Expr copyInto(Expr expr) {
expr = (Expr) super.copyInto(expr);
DefExpr def = def();
if (isDef()) {
expr.setDef(null);
} else {
expr.setDef(def);
}
return expr;
}
/**
* Returns an Object that can be used to compare other Expr to this.
*/
public Object comparator() {
return comparator;
}
/**
* ExprComparator is used to provide a different notion of equality among
* expressions than the default ==. In most cases, we want ==, but
* occasionally we want the equalsExpr() functionality when inserting in
* Hashtables, etc.
*/
private class ExprComparator {
Expr expr = Expr.this;
public boolean equals(Object obj) {
if (obj instanceof ExprComparator) {
Expr other = ((ExprComparator) obj).expr;
return expr.equalsExpr(other)
&& Assert.simple(expr.type).equals(
Assert.simple(other.type));
}
return false;
}
public int hashCode() {
return Expr.this.exprHashCode();
}
}
}

@ -0,0 +1,76 @@
/*
* Class: ExprStmt
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.tree;
/**
* ExprStmt is a statement consisting of an expression.
*
* @see Expr
*/
public class ExprStmt extends Stmt {
Expr expr; // Expression contained in this statement
/**
* Constructor.
*
* @param expr
* The expression contained in this statement.
*/
public ExprStmt(Expr expr) {
this.expr = expr;
expr.setParent(this);
}
public Expr expr() {
return expr;
}
public void visitForceChildren(TreeVisitor visitor) {
expr.visit(visitor);
}
public void visit(TreeVisitor visitor) {
visitor.visitExprStmt(this);
}
public Object clone() {
return copyInto(new ExprStmt((Expr) expr.clone()));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save